Skip to content

Commit

Permalink
feat: adding custom meshes
Browse files Browse the repository at this point in the history
  • Loading branch information
dbirman committed Feb 29, 2024
1 parent b736b61 commit 071aa5c
Show file tree
Hide file tree
Showing 12 changed files with 233 additions and 6 deletions.
1 change: 1 addition & 0 deletions API/oursin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from . import text
from . import volumes
from . import texture
from . import custom

# load the colors
from . import colors
Expand Down
70 changes: 70 additions & 0 deletions API/oursin/custom.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"""Custom 3D Objects"""

from . import client
from . import utils
import json

count = 0

class CustomMesh:
"""Custom 3D object
"""

def __init__(self, vertices, triangles, normals = None):
"""Create a Custom 3D object based on a set of vertices and triangle faces
Parameters
----------
vertices : list of vector3
Vertex coordinates
triangles : list of vector3
Triangle vertices
normals : list of vector3, optional
Normal directions, by default None
"""
global count

self.id = str(count)
count += 1

data = {}
data['ID'] = self.id
data['vertices'] = vertices
data['triangles'] = triangles

if not normals is None:
data['normals'] = normals

client.sio.emit('CustomMeshCreate', json.dumps(data))

self.in_unity = True

def delete(self):
"""Destroy this object in the renderer scene
"""
client.sio.emit('CustomMeshDelete', self.id)
self.in_unity = False

def set_position(self, position = [0,0,0], use_reference = True):
"""Set the position relative to the reference coordinate
Parameters
----------
position : vector3
AP/ML/DV coordinate relative to the reference (defaults to [0,0,0] when unset)
use_reference : bool, optional
whether to use the reference coordinate, by default True
"""
position = utils.sanitize_vector3(position)

data = {}
data['ID'] = self.id
data['Position'] = position
data['UseReference'] = use_reference

client.sio.emit('CustomMeshPosition', json.dumps(data))

def clear():
"""Clear all custom meshes
"""
client.sio.emit('Clear','custommesh')
12 changes: 11 additions & 1 deletion API/oursin/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,14 @@ def rgb_to_hex(rgb):
return '#%02x%02x%02x' % rgb

def rgba_to_hex(rgba):
return '#%02x%02x%02x%02x' % rgba
return '#%02x%02x%02x%02x' % rgba

def list_of_list2vector3(list_of_list):
"""Convert a list of lists to a list of vector3 {"x","y","z"} objects
Parameters
----------
list_of_list : list of length 3 lists
_description_
"""
return [{"x":str(data[0]), "y":str(data[1]), "z":str(data[2])} for data in list_of_list]
17 changes: 16 additions & 1 deletion UnityClient/Packages/vbl.urchin/Scripts/API/Client_SocketIO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ void Start()
Start_LineRenderer();
Start_PrimitiveMeshRenderer();
Start_FOV();
Start_CustomMesh();

// Misc
manager.Socket.On<string>("Clear", Clear);
Expand Down Expand Up @@ -261,6 +262,16 @@ private void Start_FOV()
manager.Socket.On<Dictionary<string, bool>>("SetFOVVisibility", x => SetFOVVisibility.Invoke(x));
}

public static Action<CustomMeshData> CustomMeshCreate;
public static Action<CustomMeshDestroy> CustomMeshDestroy;
public static Action<CustomMeshPosition> CustomMeshPosition;

private void Start_CustomMesh()
{
manager.Socket.On<string>("CustomMeshCreate", x => CustomMeshCreate.Invoke(JsonUtility.FromJson<CustomMeshData>(x)));
manager.Socket.On<string>("CustomMeshDestroy", x => CustomMeshDestroy.Invoke(JsonUtility.FromJson<CustomMeshDestroy>(x)));
manager.Socket.On<string>("CustomMeshPosition", x => CustomMeshPosition.Invoke(JsonUtility.FromJson<CustomMeshPosition>(x)));
}

#endregion

Expand All @@ -273,8 +284,9 @@ private void Start_FOV()
public static Action ClearParticles;
public static Action ClearMeshes;
public static Action ClearFOV;
public static Action ClearCustomMeshes;
public static List<Action> ClearAll = new List<Action> { ClearProbes, ClearAreas, ClearVolumes,
ClearText, ClearParticles, ClearMeshes, ClearFOV};
ClearText, ClearParticles, ClearMeshes, ClearFOV, ClearCustomMeshes};
private void Clear(string val)
{
switch (val)
Expand Down Expand Up @@ -304,6 +316,9 @@ private void Clear(string val)
case "texture":
ClearFOV.Invoke();
break;
case "custommesh":
ClearCustomMeshes.Invoke();
break;
}
}
#endregion
Expand Down
8 changes: 8 additions & 0 deletions UnityClient/Packages/vbl.urchin/Scripts/JSON/CustomMesh.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using UnityEngine;

public struct CustomMeshData
{
public string ID;
public Vector3[] vertices;
public Vector3Int[] triangles;
public Vector3[] normals;
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

public struct CustomMeshDestroy
{
public string ID;
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using UnityEngine;

public struct CustomMeshPosition
{
public string ID;
public Vector3 Position;
public bool UseReference;
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,21 +1,89 @@
using BrainAtlas;
using System.Collections;
using System.Collections.Generic;
using Unity.Entities.UniversalDelegates;
using UnityEngine;
using Urchin.API;

namespace Urchin.Managers
{
public class CustomMeshManager : MonoBehaviour
{
// Start is called before the first frame update
void Start()
#region Serialized
[SerializeField] private Transform _customMeshParentT;
#endregion

#region Private
Dictionary<string, GameObject> _customMeshGOs;
#endregion

private void Start()
{
_customMeshGOs = new();

Client_SocketIO.CustomMeshCreate += Create;
Client_SocketIO.CustomMeshDestroy += Destroy;
Client_SocketIO.CustomMeshPosition += SetPosition;

Client_SocketIO.ClearCustomMeshes += Clear;
}

public void Create(CustomMeshData data)
{
GameObject go = new GameObject(data.ID);
go.transform.SetParent(_customMeshParentT);

Mesh mesh = new Mesh();
mesh.vertices = data.vertices;

int[] triangles = new int[data.triangles.Length * 3];
for (int i = 0; i < data.triangles.Length; i++)
{
triangles[i + 0] = data.triangles[i].x;
triangles[i + 1] = data.triangles[i].y;
triangles[i + 2] = data.triangles[i].z;
}
mesh.triangles = triangles;

if (data.normals != null)
mesh.normals = data.normals;

go.AddComponent<MeshFilter>().mesh = mesh;
go.AddComponent<MeshRenderer>().material = MaterialManager.MeshMaterials["default"];

_customMeshGOs.Add(data.ID, go);
}

public void Destroy(CustomMeshDestroy data)
{
if (_customMeshGOs.ContainsKey(data.ID))
{
Destroy(_customMeshGOs[data.ID]);
_customMeshGOs.Remove(data.ID);
}
else
Client_SocketIO.LogWarning($"Custom mesh {data.ID} does not exist in the scene, cannot destroy");

}

public void SetPosition(CustomMeshPosition data)
{
if (_customMeshGOs.ContainsKey(data.ID))
{
Transform transform = _customMeshGOs[data.ID].transform;

transform.position = BrainAtlasManager.ActiveReferenceAtlas.Atlas2World(data.Position, data.UseReference? data.UseReference : true);
}
else
Client_SocketIO.LogWarning($"Custom mesh {data.ID} does not exist in the scene, cannot set position");
}

// Update is called once per frame
void Update()
public void Clear()
{
foreach (var kvp in _customMeshGOs)
Destroy(kvp.Value);

_customMeshGOs.Clear();
}
}

Expand Down

0 comments on commit 071aa5c

Please sign in to comment.