feat: non leaking meshes generated in editor mode
Addressed issue with unity bugging out over meshes being created in editor mode by modifying the conversion process ConverterUnity.Geometry.cs. Also modified stream manager to manage the RecursiveConverter.cs component access
This commit is contained in:
@@ -10,6 +10,9 @@
|
||||
/[Ll]ogs/
|
||||
/[Uu]ser[Ss]ettings/
|
||||
|
||||
#Test space content
|
||||
/[Tt]estSpace/
|
||||
|
||||
# MemoryCaptures can get excessive in size.
|
||||
# They also could contain extremely sensitive data
|
||||
/[Mm]emoryCaptures/
|
||||
|
||||
@@ -6,385 +6,374 @@ using System.Reflection;
|
||||
using Objects.Other;
|
||||
using Speckle.ConnectorUnity;
|
||||
using Speckle.Core.Models;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Mesh = Objects.Geometry.Mesh;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Objects.Converter.Unity
|
||||
{
|
||||
public partial class ConverterUnity
|
||||
{
|
||||
namespace Objects.Converter.Unity {
|
||||
public partial class ConverterUnity {
|
||||
#region helper methods
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
/// <param name="z"></param>
|
||||
/// <returns></returns>
|
||||
public Vector3 VectorByCoordinates( double x, double y, double z, string units )
|
||||
{
|
||||
// switch y and z
|
||||
return new Vector3( (float) ScaleToNative( x, units ), (float) ScaleToNative( z, units ),
|
||||
(float) ScaleToNative( y, units ) );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
/// <param name="z"></param>
|
||||
/// <returns></returns>
|
||||
public Vector3 VectorByCoordinates(double x, double y, double z, string units)
|
||||
{
|
||||
// switch y and z
|
||||
return new Vector3((float) ScaleToNative(x, units), (float) ScaleToNative(z, units),
|
||||
(float) ScaleToNative(y, units));
|
||||
}
|
||||
public Vector3 VectorFromPoint( Point p )
|
||||
{
|
||||
// switch y and z
|
||||
return new Vector3( (float) ScaleToNative( p.x, p.units ), (float) ScaleToNative( p.z, p.units ),
|
||||
(float) ScaleToNative( p.y, p.units ) );
|
||||
}
|
||||
|
||||
public Vector3 VectorFromPoint(Point p)
|
||||
{
|
||||
// switch y and z
|
||||
return new Vector3((float) ScaleToNative(p.x, p.units), (float) ScaleToNative(p.z, p.units),
|
||||
(float) ScaleToNative(p.y, p.units));
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="ptValues"></param>
|
||||
/// <returns></returns>
|
||||
// public Vector3 ArrayToPoint(double[] ptValues, string units)
|
||||
// {
|
||||
// double x = ptValues[0];
|
||||
// double y = ptValues[1];
|
||||
// double z = ptValues[2];
|
||||
//
|
||||
// return PointByCoordinates(x, y, z, units);
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="ptValues"></param>
|
||||
/// <returns></returns>
|
||||
// public Vector3 ArrayToPoint(double[] ptValues, string units)
|
||||
// {
|
||||
// double x = ptValues[0];
|
||||
// double y = ptValues[1];
|
||||
// double z = ptValues[2];
|
||||
//
|
||||
// return PointByCoordinates(x, y, z, units);
|
||||
// }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="arr"></param>
|
||||
/// <returns></returns>
|
||||
public Vector3[ ] ArrayToPoints( IEnumerable<double> arr, string units )
|
||||
{
|
||||
if ( arr.Count( ) % 3 != 0 ) throw new Exception( "Array malformed: length%3 != 0." );
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="arr"></param>
|
||||
/// <returns></returns>
|
||||
public Vector3[] ArrayToPoints(IEnumerable<double> arr, string units)
|
||||
{
|
||||
if (arr.Count() % 3 != 0) throw new Exception("Array malformed: length%3 != 0.");
|
||||
|
||||
Vector3[] points = new Vector3[arr.Count() / 3];
|
||||
var asArray = arr.ToArray();
|
||||
for (int i = 2, k = 0; i < arr.Count(); i += 3)
|
||||
points[k++] = VectorByCoordinates(asArray[i - 2], asArray[i - 1], asArray[i], units);
|
||||
|
||||
return points;
|
||||
}
|
||||
Vector3[ ] points = new Vector3[ arr.Count( ) / 3 ];
|
||||
var asArray = arr.ToArray( );
|
||||
for ( int i = 2, k = 0; i < arr.Count( ); i += 3 )
|
||||
points[ k++ ] = VectorByCoordinates( asArray[ i - 2 ], asArray[ i - 1 ], asArray[ i ], units );
|
||||
|
||||
return points;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ToSpeckle
|
||||
//TODO: more of these
|
||||
|
||||
//TODO: more of these
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public Point PointToSpeckle(Vector3 p)
|
||||
{
|
||||
//switch y and z
|
||||
return new Point(p.x, p.z, p.y);
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public Point PointToSpeckle( Vector3 p )
|
||||
{
|
||||
//switch y and z
|
||||
return new Point( p.x, p.z, p.y );
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Speckle mesh to a GameObject with a mesh renderer
|
||||
/// </summary>
|
||||
/// <param name="speckleMesh"></param>
|
||||
/// <returns></returns>
|
||||
public Mesh MeshToSpeckle(GameObject go)
|
||||
{
|
||||
//TODO: support multiple filters?
|
||||
var filter = go.GetComponent<MeshFilter>();
|
||||
if (filter == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts a Speckle mesh to a GameObject with a mesh renderer
|
||||
/// </summary>
|
||||
/// <param name="speckleMesh"></param>
|
||||
/// <returns></returns>
|
||||
public Mesh MeshToSpeckle( GameObject go )
|
||||
{
|
||||
//TODO: support multiple filters?
|
||||
var filter = go.GetComponent<MeshFilter>( );
|
||||
if ( filter == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//convert triangle array into speckleMesh faces
|
||||
List<int> faces = new List<int>();
|
||||
int i = 0;
|
||||
//store them here, makes it like 1000000x faster?
|
||||
var triangles = filter.mesh.triangles;
|
||||
while (i < triangles.Length)
|
||||
{
|
||||
faces.Add(0);
|
||||
//convert triangle array into speckleMesh faces
|
||||
List<int> faces = new List<int>( );
|
||||
int i = 0;
|
||||
//store them here, makes it like 1000000x faster?
|
||||
var triangles = filter.mesh.triangles;
|
||||
while (i < triangles.Length) {
|
||||
faces.Add( 0 );
|
||||
|
||||
faces.Add(triangles[i + 0]);
|
||||
faces.Add(triangles[i + 2]);
|
||||
faces.Add(triangles[i + 1]);
|
||||
i += 3;
|
||||
}
|
||||
faces.Add( triangles[ i + 0 ] );
|
||||
faces.Add( triangles[ i + 2 ] );
|
||||
faces.Add( triangles[ i + 1 ] );
|
||||
i += 3;
|
||||
}
|
||||
|
||||
var mesh = new Mesh();
|
||||
// get the speckle data from the go here
|
||||
// so that if the go comes from speckle, typed props will get overridden below
|
||||
AttachUnityProperties(mesh, go);
|
||||
var mesh = new Mesh( );
|
||||
// get the speckle data from the go here
|
||||
// so that if the go comes from speckle, typed props will get overridden below
|
||||
AttachUnityProperties( mesh, go );
|
||||
|
||||
mesh.units = ModelUnits;
|
||||
mesh.units = ModelUnits;
|
||||
|
||||
var vertices = filter.mesh.vertices;
|
||||
foreach (var vertex in vertices)
|
||||
{
|
||||
var p = go.transform.TransformPoint(vertex);
|
||||
var sp = PointToSpeckle(p);
|
||||
mesh.vertices.Add(sp.x);
|
||||
mesh.vertices.Add(sp.y);
|
||||
mesh.vertices.Add(sp.z);
|
||||
}
|
||||
var vertices = filter.mesh.vertices;
|
||||
foreach ( var vertex in vertices ) {
|
||||
var p = go.transform.TransformPoint( vertex );
|
||||
var sp = PointToSpeckle( p );
|
||||
mesh.vertices.Add( sp.x );
|
||||
mesh.vertices.Add( sp.y );
|
||||
mesh.vertices.Add( sp.z );
|
||||
}
|
||||
|
||||
mesh.faces = faces;
|
||||
|
||||
return mesh;
|
||||
}
|
||||
mesh.faces = faces;
|
||||
|
||||
return mesh;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ToNative
|
||||
private GameObject NewPointBasedGameObject( Vector3[ ] points, string name )
|
||||
{
|
||||
if ( points.Length == 0 ) return null;
|
||||
|
||||
private GameObject NewPointBasedGameObject(Vector3[] points, string name)
|
||||
{
|
||||
if (points.Length == 0) return null;
|
||||
float pointDiameter = 1; //TODO: figure out how best to change this?
|
||||
|
||||
float pointDiameter = 1; //TODO: figure out how best to change this?
|
||||
var go = new GameObject( );
|
||||
go.name = name;
|
||||
|
||||
var go = new GameObject();
|
||||
go.name = name;
|
||||
var lineRenderer = go.AddComponent<LineRenderer>( );
|
||||
|
||||
var lineRenderer = go.AddComponent<LineRenderer>();
|
||||
lineRenderer.positionCount = points.Length;
|
||||
lineRenderer.SetPositions( points );
|
||||
lineRenderer.numCornerVertices = lineRenderer.numCapVertices = 8;
|
||||
lineRenderer.startWidth = lineRenderer.endWidth = pointDiameter;
|
||||
|
||||
lineRenderer.positionCount = points.Length;
|
||||
lineRenderer.SetPositions(points);
|
||||
lineRenderer.numCornerVertices = lineRenderer.numCapVertices = 8;
|
||||
lineRenderer.startWidth = lineRenderer.endWidth = pointDiameter;
|
||||
return go;
|
||||
}
|
||||
|
||||
return go;
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts a Speckle point to a GameObject with a line renderer
|
||||
/// </summary>
|
||||
/// <param name="point"></param>
|
||||
/// <returns></returns>
|
||||
public GameObject PointToNative( Point point )
|
||||
{
|
||||
Vector3 newPt = VectorByCoordinates( point.x, point.y, point.z, point.units );
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Speckle point to a GameObject with a line renderer
|
||||
/// </summary>
|
||||
/// <param name="point"></param>
|
||||
/// <returns></returns>
|
||||
public GameObject PointToNative(Point point)
|
||||
{
|
||||
Vector3 newPt = VectorByCoordinates(point.x, point.y, point.z, point.units);
|
||||
|
||||
var go = NewPointBasedGameObject(new Vector3[2] {newPt, newPt}, point.speckle_type);
|
||||
return go;
|
||||
}
|
||||
var go = NewPointBasedGameObject( new Vector3[ 2 ] {newPt, newPt}, point.speckle_type );
|
||||
return go;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Speckle line to a GameObject with a line renderer
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
public GameObject LineToNative(Line line)
|
||||
{
|
||||
var points = new List<Vector3> {VectorFromPoint(line.start), VectorFromPoint(line.end)};
|
||||
/// <summary>
|
||||
/// Converts a Speckle line to a GameObject with a line renderer
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
public GameObject LineToNative( Line line )
|
||||
{
|
||||
var points = new List<Vector3> {VectorFromPoint( line.start ), VectorFromPoint( line.end )};
|
||||
|
||||
var go = NewPointBasedGameObject(points.ToArray(), line.speckle_type);
|
||||
return go;
|
||||
}
|
||||
var go = NewPointBasedGameObject( points.ToArray( ), line.speckle_type );
|
||||
return go;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Speckle polyline to a GameObject with a line renderer
|
||||
/// </summary>
|
||||
/// <param name="polyline"></param>
|
||||
/// <returns></returns>
|
||||
public GameObject PolylineToNative(Polyline polyline)
|
||||
{
|
||||
var points = polyline.points.Select(x => VectorFromPoint(x));
|
||||
/// <summary>
|
||||
/// Converts a Speckle polyline to a GameObject with a line renderer
|
||||
/// </summary>
|
||||
/// <param name="polyline"></param>
|
||||
/// <returns></returns>
|
||||
public GameObject PolylineToNative( Polyline polyline )
|
||||
{
|
||||
var points = polyline.points.Select( x => VectorFromPoint( x ) );
|
||||
|
||||
var go = NewPointBasedGameObject(points.ToArray(), polyline.speckle_type);
|
||||
return go;
|
||||
}
|
||||
var go = NewPointBasedGameObject( points.ToArray( ), polyline.speckle_type );
|
||||
return go;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Speckle curve to a GameObject with a line renderer
|
||||
/// </summary>
|
||||
/// <param name="curve"></param>
|
||||
/// <returns></returns>
|
||||
public GameObject CurveToNative(Curve curve)
|
||||
{
|
||||
var points = ArrayToPoints(curve.points, curve.units);
|
||||
var go = NewPointBasedGameObject(points.ToArray(), curve.speckle_type);
|
||||
return go;
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts a Speckle curve to a GameObject with a line renderer
|
||||
/// </summary>
|
||||
/// <param name="curve"></param>
|
||||
/// <returns></returns>
|
||||
public GameObject CurveToNative( Curve curve )
|
||||
{
|
||||
var points = ArrayToPoints( curve.points, curve.units );
|
||||
var go = NewPointBasedGameObject( points.ToArray( ), curve.speckle_type );
|
||||
return go;
|
||||
}
|
||||
|
||||
|
||||
public GameObject MeshToNative(Base speckleMeshObject)
|
||||
{
|
||||
if (!(speckleMeshObject["displayMesh"] is Mesh))
|
||||
return null;
|
||||
public GameObject MeshToNative( Base speckleMeshObject )
|
||||
{
|
||||
if ( !( speckleMeshObject[ "displayMesh" ] is Mesh ) )
|
||||
return null;
|
||||
|
||||
return MeshToNative(speckleMeshObject["displayMesh"] as Mesh,
|
||||
speckleMeshObject["renderMaterial"] as RenderMaterial, speckleMeshObject.GetMembers());
|
||||
}
|
||||
return MeshToNative( speckleMeshObject[ "displayMesh" ] as Mesh,
|
||||
speckleMeshObject[ "renderMaterial" ] as RenderMaterial, speckleMeshObject.GetMembers( ) );
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Speckle mesh to a GameObject with a mesh renderer
|
||||
/// </summary>
|
||||
/// <param name="speckleMesh">Mesh to convert</param>
|
||||
/// <param name="renderMaterial">If provided will override the renderMaterial on the mesh itself</param>
|
||||
/// <param name="properties">If provided will override the properties on the mesh itself</param>
|
||||
/// <returns></returns>
|
||||
public GameObject MeshToNative(Mesh speckleMesh, RenderMaterial renderMaterial = null,
|
||||
Dictionary<string, object> properties = null)
|
||||
{
|
||||
if (speckleMesh.vertices.Count == 0 || speckleMesh.faces.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts a Speckle mesh to a GameObject with a mesh renderer
|
||||
/// </summary>
|
||||
/// <param name="speckleMesh">Mesh to convert</param>
|
||||
/// <param name="renderMaterial">If provided will override the renderMaterial on the mesh itself</param>
|
||||
/// <param name="properties">If provided will override the properties on the mesh itself</param>
|
||||
/// <returns></returns>
|
||||
public GameObject MeshToNative(
|
||||
Mesh speckleMesh, RenderMaterial renderMaterial = null,
|
||||
Dictionary<string, object> properties = null
|
||||
)
|
||||
{
|
||||
if ( speckleMesh.vertices.Count == 0 || speckleMesh.faces.Count == 0 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var recentreMeshTransforms = true; //TODO: figure out how best to change this?
|
||||
|
||||
var verts = ArrayToPoints(speckleMesh.vertices, speckleMesh.units).ToList();
|
||||
//convert speckleMesh.faces into triangle array
|
||||
List<int> tris = new List<int>();
|
||||
int i = 0;
|
||||
while (i < speckleMesh.faces.Count)
|
||||
{
|
||||
if (speckleMesh.faces[i] == 0)
|
||||
{
|
||||
//Triangles
|
||||
tris.Add(speckleMesh.faces[i + 1]);
|
||||
tris.Add(speckleMesh.faces[i + 3]);
|
||||
tris.Add(speckleMesh.faces[i + 2]);
|
||||
i += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Quads to triangles
|
||||
tris.Add(speckleMesh.faces[i + 1]);
|
||||
tris.Add(speckleMesh.faces[i + 3]);
|
||||
tris.Add(speckleMesh.faces[i + 2]);
|
||||
|
||||
tris.Add(speckleMesh.faces[i + 1]);
|
||||
tris.Add(speckleMesh.faces[i + 4]);
|
||||
tris.Add(speckleMesh.faces[i + 3]);
|
||||
|
||||
i += 5;
|
||||
}
|
||||
}
|
||||
var recenterMeshTransforms = true; //TODO: figure out how best to change this?
|
||||
|
||||
|
||||
var go = new GameObject();
|
||||
go.name = speckleMesh.speckle_type;
|
||||
var verts = ArrayToPoints( speckleMesh.vertices, speckleMesh.units );
|
||||
|
||||
var mesh = go.AddComponent<MeshFilter>().mesh;
|
||||
var meshRenderer = go.AddComponent<MeshRenderer>();
|
||||
//convert speckleMesh.faces into triangle array
|
||||
List<int> tris = new List<int>( );
|
||||
int i = 0;
|
||||
while (i < speckleMesh.faces.Count) {
|
||||
if ( speckleMesh.faces[ i ] == 0 ) {
|
||||
//Triangles
|
||||
tris.Add( speckleMesh.faces[ i + 1 ] );
|
||||
tris.Add( speckleMesh.faces[ i + 3 ] );
|
||||
tris.Add( speckleMesh.faces[ i + 2 ] );
|
||||
i += 4;
|
||||
} else {
|
||||
//Quads to triangles
|
||||
tris.Add( speckleMesh.faces[ i + 1 ] );
|
||||
tris.Add( speckleMesh.faces[ i + 3 ] );
|
||||
tris.Add( speckleMesh.faces[ i + 2 ] );
|
||||
|
||||
var speckleMaterial = renderMaterial ?? (RenderMaterial)speckleMesh["renderMaterial"];
|
||||
meshRenderer.material = GetMaterial(speckleMaterial);
|
||||
tris.Add( speckleMesh.faces[ i + 1 ] );
|
||||
tris.Add( speckleMesh.faces[ i + 4 ] );
|
||||
tris.Add( speckleMesh.faces[ i + 3 ] );
|
||||
|
||||
i += 5;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (verts.Count >= 65535)
|
||||
mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
|
||||
var go = new GameObject {name = speckleMesh.speckle_type};
|
||||
var mesh = new UnityEngine.Mesh {name = speckleMesh.speckle_type};
|
||||
|
||||
// center transform pivot according to the bounds of the model
|
||||
if (recentreMeshTransforms)
|
||||
{
|
||||
Bounds meshBounds = new Bounds();
|
||||
meshBounds.center = verts[0];
|
||||
|
||||
verts.ForEach(x => meshBounds.Encapsulate(x));
|
||||
|
||||
go.transform.position = meshBounds.center;
|
||||
|
||||
// offset mesh vertices
|
||||
for (int l = 0; l < verts.Count; l++)
|
||||
{
|
||||
verts[l] -= meshBounds.center;
|
||||
}
|
||||
}
|
||||
|
||||
// assign mesh properties
|
||||
mesh.vertices = verts.ToArray();
|
||||
mesh.triangles = tris.ToArray();
|
||||
if ( verts.Length >= 65535 )
|
||||
mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
|
||||
|
||||
|
||||
mesh.Optimize();
|
||||
mesh.RecalculateNormals();
|
||||
mesh.RecalculateTangents();
|
||||
// center transform pivot according to the bounds of the model
|
||||
if ( recenterMeshTransforms ) {
|
||||
Bounds meshBounds = new Bounds {
|
||||
center = verts[ 0 ]
|
||||
};
|
||||
|
||||
foreach ( var vert in verts ) {
|
||||
meshBounds.Encapsulate( vert );
|
||||
}
|
||||
// verts.ForEach( x => meshBounds.Encapsulate( x ) );
|
||||
|
||||
go.transform.position = meshBounds.center;
|
||||
|
||||
// offset mesh vertices
|
||||
for ( int l = 0; l < verts.Length; l++ ) {
|
||||
verts[ l ] -= meshBounds.center;
|
||||
}
|
||||
}
|
||||
|
||||
mesh.SetVertices( verts );
|
||||
mesh.SetTriangles( tris, 0 );
|
||||
|
||||
mesh.RecalculateNormals( );
|
||||
mesh.RecalculateBounds( );
|
||||
mesh.Optimize( );
|
||||
|
||||
|
||||
//generate uvs doesn't work as intended. Leaving out for now
|
||||
//GenerateUVs (ref mesh);
|
||||
//generate uvs doesn't work as intended. Leaving out for now
|
||||
//GenerateUVs (ref mesh);
|
||||
|
||||
//Add mesh collider
|
||||
MeshCollider mc = go.AddComponent<MeshCollider>();
|
||||
mc.sharedMesh = mesh;
|
||||
//mc.convex = true;
|
||||
// Setting mesh to filter once all mesh modifying is done
|
||||
go.SafeMeshSet( mesh, true );
|
||||
// go.AddComponent<MeshFilter>( ).mesh = mesh;
|
||||
|
||||
|
||||
//attach properties on this very mesh
|
||||
//means the mesh originated in Rhino or similar
|
||||
if (properties == null)
|
||||
{
|
||||
var meshprops = typeof(Mesh).GetProperties(BindingFlags.Instance | BindingFlags.Public).Select(x => x.Name)
|
||||
.ToList();
|
||||
properties = speckleMesh.GetMembers()
|
||||
.Where(x => !meshprops.Contains(x.Key))
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
}
|
||||
var meshRenderer = go.AddComponent<MeshRenderer>( );
|
||||
var speckleMaterial = renderMaterial ?? (RenderMaterial) speckleMesh[ "renderMaterial" ];
|
||||
meshRenderer.sharedMaterial = GetMaterial( speckleMaterial );
|
||||
|
||||
AttachSpeckleProperties(go, properties);
|
||||
return go;
|
||||
}
|
||||
//Add mesh collider
|
||||
// MeshCollider mc = go.AddComponent<MeshCollider>( );
|
||||
// mc.sharedMesh = mesh;
|
||||
//mc.convex = true;
|
||||
|
||||
|
||||
//attach properties on this very mesh
|
||||
//means the mesh originated in Rhino or similar
|
||||
if ( properties == null ) {
|
||||
var meshprops = typeof( Mesh ).GetProperties( BindingFlags.Instance | BindingFlags.Public ).Select( x => x.Name )
|
||||
.ToList( );
|
||||
properties = speckleMesh.GetMembers( )
|
||||
.Where( x => !meshprops.Contains( x.Key ) )
|
||||
.ToDictionary( x => x.Key, x => x.Value );
|
||||
}
|
||||
|
||||
AttachSpeckleProperties( go, properties );
|
||||
return go;
|
||||
}
|
||||
#endregion
|
||||
|
||||
private Material GetMaterial(RenderMaterial renderMaterial)
|
||||
{
|
||||
//todo support more complex materials
|
||||
var shader = Shader.Find("Standard");
|
||||
Material mat = new Material(shader);
|
||||
private Material GetMaterial( RenderMaterial renderMaterial )
|
||||
{
|
||||
//todo support more complex materials
|
||||
var shader = Shader.Find( "Standard" );
|
||||
Material mat = new Material( shader );
|
||||
|
||||
//if a renderMaterial is passed use that, otherwise try get it from the mesh itself
|
||||
//if a renderMaterial is passed use that, otherwise try get it from the mesh itself
|
||||
|
||||
if (renderMaterial != null)
|
||||
{
|
||||
// 1. match material by name, if any
|
||||
var matByName = ContextObjects.FirstOrDefault(x => ((Material)x.NativeObject).name == renderMaterial.name);
|
||||
if (matByName!=null)
|
||||
{
|
||||
return matByName.NativeObject as Material;
|
||||
}
|
||||
|
||||
// 2. re-create material by setting diffuse color and transparency on standard shaders
|
||||
if (renderMaterial.opacity < 1)
|
||||
{
|
||||
shader = Shader.Find("Transparent/Diffuse");
|
||||
mat = new Material(shader);
|
||||
}
|
||||
if ( renderMaterial != null ) {
|
||||
// 1. match material by name, if any
|
||||
var matByName = ContextObjects.FirstOrDefault( x => ( (Material) x.NativeObject ).name == renderMaterial.name );
|
||||
if ( matByName != null ) {
|
||||
return matByName.NativeObject as Material;
|
||||
}
|
||||
|
||||
var c = renderMaterial.diffuse.ToUnityColor();
|
||||
mat.color = new Color(c.r, c.g, c.b, Convert.ToSingle(renderMaterial.opacity));
|
||||
// 2. re-create material by setting diffuse color and transparency on standard shaders
|
||||
if ( renderMaterial.opacity < 1 ) {
|
||||
shader = Shader.Find( "Transparent/Diffuse" );
|
||||
mat = new Material( shader );
|
||||
}
|
||||
|
||||
return mat;
|
||||
}
|
||||
var c = renderMaterial.diffuse.ToUnityColor( );
|
||||
mat.color = new Color( c.r, c.g, c.b, Convert.ToSingle( renderMaterial.opacity ) );
|
||||
|
||||
// 3. if not renderMaterial was passed, the default shader will be used
|
||||
return mat;
|
||||
return mat;
|
||||
}
|
||||
|
||||
// 3. if not renderMaterial was passed, the default shader will be used
|
||||
return mat;
|
||||
}
|
||||
|
||||
private void AttachSpeckleProperties( GameObject go, Dictionary<string, object> properties )
|
||||
{
|
||||
var sd = go.AddComponent<SpeckleProperties>( );
|
||||
sd.Data = properties;
|
||||
}
|
||||
|
||||
|
||||
private void AttachUnityProperties( Base @base, GameObject go )
|
||||
{
|
||||
var sd = go.GetComponent<SpeckleProperties>( );
|
||||
if ( sd == null || sd.Data == null )
|
||||
return;
|
||||
|
||||
foreach ( var key in sd.Data.Keys ) {
|
||||
@base[ key ] = sd.Data[ key ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AttachSpeckleProperties(GameObject go, Dictionary<string, object> properties)
|
||||
{
|
||||
var sd = go.AddComponent<SpeckleProperties>();
|
||||
sd.Data = properties;
|
||||
}
|
||||
|
||||
|
||||
private void AttachUnityProperties(Base @base, GameObject go)
|
||||
{
|
||||
var sd = go.GetComponent<SpeckleProperties>();
|
||||
if (sd == null || sd.Data == null)
|
||||
return;
|
||||
foreach (var key in sd.Data.Keys)
|
||||
{
|
||||
@base[key] = sd.Data[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ namespace Objects.Converter.Unity
|
||||
|
||||
|
||||
public List<ApplicationPlaceholderObject> ContextObjects { get; set; } = new List<ApplicationPlaceholderObject>();
|
||||
|
||||
public void SetContextDocument(object doc) => throw new NotImplementedException();
|
||||
|
||||
public void SetContextObjects(List<ApplicationPlaceholderObject> objects) => ContextObjects = objects;
|
||||
|
||||
@@ -8,184 +8,158 @@ using Speckle.Core.Logging;
|
||||
using Speckle.Core.Models;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Speckle.ConnectorUnity
|
||||
{
|
||||
public class RecursiveConverter : MonoBehaviour
|
||||
{
|
||||
namespace Speckle.ConnectorUnity {
|
||||
public class RecursiveConverter : MonoBehaviour {
|
||||
|
||||
private ConverterUnity _converter = new ConverterUnity();
|
||||
private ConverterUnity _converter = new ConverterUnity( );
|
||||
|
||||
public RecursiveConverter()
|
||||
{
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts a Base object to a GameObject Recursively
|
||||
/// </summary>
|
||||
/// <param name="base"></param>
|
||||
/// <returns></returns>
|
||||
public GameObject ConvertRecursivelyToNative(Base @base, string name)
|
||||
{
|
||||
//using the ApplicationPlaceholderObject to pass materials
|
||||
//available in Assets/Materials to the converters
|
||||
var materials = Resources.LoadAll("Materials", typeof(Material)).Cast<Material>()
|
||||
.Select(x => new ApplicationPlaceholderObject {NativeObject = x}).ToList();
|
||||
_converter.SetContextObjects(materials);
|
||||
|
||||
|
||||
|
||||
// case 1: it's an item that has a direct conversion method, eg a point
|
||||
if (_converter.CanConvertToNative(@base))
|
||||
{
|
||||
var go = TryConvertItemToNative(@base);
|
||||
return go;
|
||||
}
|
||||
|
||||
// case 2: it's a wrapper Base
|
||||
// 2a: if there's only one member unpack it
|
||||
// 2b: otherwise return dictionary of unpacked members
|
||||
var members = @base.GetMemberNames().ToList();
|
||||
if (members.Count() == 1)
|
||||
{
|
||||
var go = RecurseTreeToNative(@base[members.First()]);
|
||||
go.name = members.First();
|
||||
return go;
|
||||
}
|
||||
else
|
||||
{
|
||||
//empty game object with the commit id as name, used to contain all the rest
|
||||
var go = new GameObject();
|
||||
go.name = name;
|
||||
foreach (var member in members)
|
||||
{
|
||||
var goo = RecurseTreeToNative(@base[member]);
|
||||
if (goo != null)
|
||||
{
|
||||
goo.name = member;
|
||||
goo.transform.parent = go.transform;
|
||||
}
|
||||
}
|
||||
|
||||
return go;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Converts an object recursively to a list of GameObjects
|
||||
/// </summary>
|
||||
/// <param name="object"></param>
|
||||
/// <returns></returns>
|
||||
private GameObject RecurseTreeToNative(object @object)
|
||||
{
|
||||
if (IsList(@object))
|
||||
{
|
||||
var list = ((IEnumerable) @object).Cast<object>();
|
||||
var objects = list.Select(x => RecurseTreeToNative(x)).Where(x => x != null).ToList();
|
||||
if (objects.Any())
|
||||
{
|
||||
var go = new GameObject();
|
||||
go.name = "List";
|
||||
objects.ForEach(x => x.transform.parent = go.transform);
|
||||
return go;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return TryConvertItemToNative(@object);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private GameObject TryConvertItemToNative(object value)
|
||||
{
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
//it's a simple type or not a Base
|
||||
if (value.GetType().IsSimpleType() || !(value is Base))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var @base = (Base) value;
|
||||
|
||||
//it's an unsupported Base, go through each of its property and try convert that
|
||||
if (!_converter.CanConvertToNative(@base))
|
||||
{
|
||||
var members = @base.GetMemberNames().ToList();
|
||||
|
||||
//empty game object with the commit id as name, used to contain all the rest
|
||||
var go = new GameObject();
|
||||
go.name = @base.speckle_type;
|
||||
var goos = new List<GameObject>();
|
||||
foreach (var member in members)
|
||||
{
|
||||
var goo = RecurseTreeToNative(@base[member]);
|
||||
if (goo != null)
|
||||
{
|
||||
goo.name = member;
|
||||
goo.transform.parent = go.transform;
|
||||
goos.Add(goo);
|
||||
}
|
||||
}
|
||||
|
||||
//if no children is valid, return null
|
||||
if (!goos.Any())
|
||||
{
|
||||
Destroy(go);
|
||||
return null;
|
||||
}
|
||||
|
||||
return go;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
var go = _converter.ConvertToNative(@base) as GameObject;
|
||||
// Some revit elements have nested elements in a "elements" property
|
||||
// for instance hosted families on a wall
|
||||
if (go != null && @base["elements"] is List<Base> l && l.Any())
|
||||
{
|
||||
var goo = RecurseTreeToNative(l);
|
||||
if (goo != null)
|
||||
/// <summary>
|
||||
/// Converts a Base object to a GameObject Recursively
|
||||
/// </summary>
|
||||
/// <param name="base"></param>
|
||||
/// <returns></returns>
|
||||
public GameObject ConvertRecursivelyToNative( Base @base, string name )
|
||||
{
|
||||
goo.name = "elements";
|
||||
goo.transform.parent = go.transform;
|
||||
//using the ApplicationPlaceholderObject to pass materials
|
||||
//available in Assets/Materials to the converters
|
||||
var materials = Resources.LoadAll( "Materials", typeof( Material ) ).Cast<Material>( )
|
||||
.Select( x => new ApplicationPlaceholderObject {NativeObject = x} ).ToList( );
|
||||
_converter.SetContextObjects( materials );
|
||||
|
||||
|
||||
// case 1: it's an item that has a direct conversion method, eg a point
|
||||
if ( _converter.CanConvertToNative( @base ) ) {
|
||||
var go = TryConvertItemToNative( @base );
|
||||
return go;
|
||||
}
|
||||
|
||||
// case 2: it's a wrapper Base
|
||||
// 2a: if there's only one member unpack it
|
||||
// 2b: otherwise return dictionary of unpacked members
|
||||
var members = @base.GetMemberNames( ).ToList( );
|
||||
if ( members.Count( ) == 1 ) {
|
||||
var go = RecurseTreeToNative( @base[ members.First( ) ] );
|
||||
go.name = members.First( );
|
||||
return go;
|
||||
} else {
|
||||
//empty game object with the commit id as name, used to contain all the rest
|
||||
var go = new GameObject {
|
||||
name = name.Valid( ) ? name : "Base"
|
||||
};
|
||||
|
||||
foreach ( var member in members ) {
|
||||
var goo = RecurseTreeToNative( @base[ member ] );
|
||||
if ( goo != null ) {
|
||||
goo.name = member;
|
||||
goo.transform.parent = go.transform;
|
||||
}
|
||||
}
|
||||
|
||||
return go;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return go;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new SpeckleException(e.Message, e, true, SentryLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
/// <summary>
|
||||
/// Converts an object recursively to a list of GameObjects
|
||||
/// </summary>
|
||||
/// <param name="object"></param>
|
||||
/// <returns></returns>
|
||||
private GameObject RecurseTreeToNative( object @object )
|
||||
{
|
||||
if ( IsList( @object ) ) {
|
||||
var list = ( (IEnumerable) @object ).Cast<object>( );
|
||||
var objects = list.Select( x => RecurseTreeToNative( x ) ).Where( x => x != null ).ToList( );
|
||||
if ( objects.Any( ) ) {
|
||||
var go = new GameObject( );
|
||||
go.name = "List";
|
||||
objects.ForEach( x => x.transform.parent = go.transform );
|
||||
return go;
|
||||
}
|
||||
} else {
|
||||
return TryConvertItemToNative( @object );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private GameObject TryConvertItemToNative( object value )
|
||||
{
|
||||
if ( value == null )
|
||||
return null;
|
||||
|
||||
//it's a simple type or not a Base
|
||||
if ( value.GetType( ).IsSimpleType( ) || !( value is Base ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var @base = (Base) value;
|
||||
|
||||
//it's an unsupported Base, go through each of its property and try convert that
|
||||
if ( !_converter.CanConvertToNative( @base ) ) {
|
||||
var members = @base.GetMemberNames( ).ToList( );
|
||||
|
||||
//empty game object with the commit id as name, used to contain all the rest
|
||||
var go = new GameObject( );
|
||||
go.name = @base.speckle_type;
|
||||
var goos = new List<GameObject>( );
|
||||
foreach ( var member in members ) {
|
||||
var goo = RecurseTreeToNative( @base[ member ] );
|
||||
if ( goo != null ) {
|
||||
goo.name = member;
|
||||
goo.transform.parent = go.transform;
|
||||
goos.Add( goo );
|
||||
}
|
||||
}
|
||||
|
||||
//if no children is valid, return null
|
||||
if ( !goos.Any( ) ) {
|
||||
Utils.SafeDestroy( go );
|
||||
return null;
|
||||
}
|
||||
|
||||
return go;
|
||||
} else {
|
||||
try {
|
||||
var go = _converter.ConvertToNative( @base ) as GameObject;
|
||||
// Some revit elements have nested elements in a "elements" property
|
||||
// for instance hosted families on a wall
|
||||
if ( go != null && @base[ "elements" ] is List<Base> l && l.Any( ) ) {
|
||||
var goo = RecurseTreeToNative( l );
|
||||
if ( goo != null ) {
|
||||
goo.name = "elements";
|
||||
goo.transform.parent = go.transform;
|
||||
}
|
||||
}
|
||||
|
||||
return go;
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
throw new SpeckleException( e.Message, e, true, SentryLevel.Error );
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private static bool IsList( object @object )
|
||||
{
|
||||
if ( @object == null )
|
||||
return false;
|
||||
|
||||
var type = @object.GetType( );
|
||||
return ( typeof( IEnumerable ).IsAssignableFrom( type ) && !typeof( IDictionary ).IsAssignableFrom( type ) &&
|
||||
type != typeof( string ) );
|
||||
}
|
||||
|
||||
private static bool IsDictionary( object @object )
|
||||
{
|
||||
if ( @object == null )
|
||||
return false;
|
||||
|
||||
Type type = @object.GetType( );
|
||||
return type.IsGenericType && type.GetGenericTypeDefinition( ) == typeof( Dictionary<,> );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static bool IsList(object @object)
|
||||
{
|
||||
if (@object == null)
|
||||
return false;
|
||||
|
||||
var type = @object.GetType();
|
||||
return (typeof(IEnumerable).IsAssignableFrom(type) && !typeof(IDictionary).IsAssignableFrom(type) &&
|
||||
type != typeof(string));
|
||||
}
|
||||
|
||||
private static bool IsDictionary(object @object)
|
||||
{
|
||||
if (@object == null)
|
||||
return false;
|
||||
|
||||
Type type = @object.GetType();
|
||||
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,30 +5,39 @@ using Speckle.Core.Credentials;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Speckle.Core.Models;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Speckle.ConnectorUnity
|
||||
{
|
||||
[ExecuteAlways]
|
||||
public class StreamManager : MonoBehaviour
|
||||
{
|
||||
namespace Speckle.ConnectorUnity {
|
||||
[ExecuteAlways]
|
||||
public class StreamManager : MonoBehaviour {
|
||||
|
||||
public int SelectedAccountIndex = -1;
|
||||
public int SelectedStreamIndex = -1;
|
||||
public int SelectedBranchIndex = -1;
|
||||
public int SelectedCommitIndex = -1;
|
||||
public int OldSelectedAccountIndex = -1;
|
||||
public int OldSelectedStreamIndex = -1;
|
||||
|
||||
public Client Client;
|
||||
public Account SelectedAccount;
|
||||
public Stream SelectedStream;
|
||||
public int SelectedAccountIndex = -1;
|
||||
public int SelectedStreamIndex = -1;
|
||||
public int SelectedBranchIndex = -1;
|
||||
public int SelectedCommitIndex = -1;
|
||||
public int OldSelectedAccountIndex = -1;
|
||||
public int OldSelectedStreamIndex = -1;
|
||||
|
||||
public List<Account> Accounts;
|
||||
public List<Stream> Streams;
|
||||
public List<Branch> Branches;
|
||||
public Client Client;
|
||||
public Account SelectedAccount;
|
||||
public Stream SelectedStream;
|
||||
|
||||
}
|
||||
public List<Account> Accounts;
|
||||
public List<Stream> Streams;
|
||||
public List<Branch> Branches;
|
||||
|
||||
public GameObject ConvertRecursivelyToNative( Base @base, string id )
|
||||
{
|
||||
|
||||
var rc = GetComponent<RecursiveConverter>( );
|
||||
if ( rc == null )
|
||||
rc = gameObject.AddComponent<RecursiveConverter>( );
|
||||
|
||||
return rc.ConvertRecursivelyToNative( @base,
|
||||
Branches[ SelectedBranchIndex ].commits.items[ SelectedCommitIndex ].id );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,69 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Speckle.ConnectorUnity
|
||||
{
|
||||
public static class Utils
|
||||
{
|
||||
public static int ToIntColor(this Color c)
|
||||
{
|
||||
return
|
||||
System.Drawing.Color
|
||||
.FromArgb(Convert.ToInt32(c.r * 255), Convert.ToInt32(c.r * 255), Convert.ToInt32(c.r * 255))
|
||||
.ToArgb();
|
||||
}
|
||||
namespace Speckle.ConnectorUnity {
|
||||
public static class Utils {
|
||||
|
||||
public static void SafeDestroy( UnityEngine.Object obj )
|
||||
{
|
||||
if ( Application.isPlaying )
|
||||
UnityEngine.Object.Destroy( obj );
|
||||
|
||||
else
|
||||
UnityEngine.Object.DestroyImmediate( obj );
|
||||
|
||||
}
|
||||
|
||||
public static bool Valid( this string name ) => !string.IsNullOrEmpty( name );
|
||||
|
||||
public static Mesh SafeMeshGet( this MeshFilter mf ) => Application.isPlaying ? mf.mesh : mf.sharedMesh;
|
||||
|
||||
|
||||
|
||||
public static void SafeMeshSet( this GameObject go, Mesh m, bool addMeshFilterIfNotFound )
|
||||
{
|
||||
|
||||
var mf = go.GetComponent<MeshFilter>( );
|
||||
if ( mf == null ) {
|
||||
if(!addMeshFilterIfNotFound) return;
|
||||
|
||||
mf = go.AddComponent<MeshFilter>( );
|
||||
}
|
||||
|
||||
|
||||
if ( Application.isPlaying )
|
||||
mf.mesh = m;
|
||||
else
|
||||
mf.sharedMesh = m;
|
||||
}
|
||||
|
||||
|
||||
public static void SafeMeshSet( this GameObject go, Mesh m )
|
||||
{
|
||||
var mf = go.GetComponent<MeshFilter>( );
|
||||
if ( mf == null ) return;
|
||||
|
||||
|
||||
if ( Application.isPlaying )
|
||||
mf.mesh = m;
|
||||
else
|
||||
mf.sharedMesh = m;
|
||||
}
|
||||
|
||||
|
||||
public static int ToIntColor( this Color c )
|
||||
{
|
||||
return
|
||||
System.Drawing.Color
|
||||
.FromArgb( Convert.ToInt32( c.r * 255 ), Convert.ToInt32( c.r * 255 ), Convert.ToInt32( c.r * 255 ) )
|
||||
.ToArgb( );
|
||||
}
|
||||
|
||||
public static Color ToUnityColor( this int c )
|
||||
{
|
||||
var argb = System.Drawing.Color.FromArgb( c );
|
||||
return new Color( argb.R / 255.0f, argb.G / 255.0f, argb.B / 255.0f );
|
||||
}
|
||||
|
||||
public static Color ToUnityColor(this int c)
|
||||
{
|
||||
var argb = System.Drawing.Color.FromArgb(c);
|
||||
return new Color(argb.R / 255.0f, argb.G / 255.0f, argb.B / 255.0f);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user