diff --git a/Assets/Speckle Connector/ConverterUnity.Geometry.cs b/Assets/Speckle Connector/ConverterUnity.Geometry.cs index a55207d..4682c0b 100644 --- a/Assets/Speckle Connector/ConverterUnity.Geometry.cs +++ b/Assets/Speckle Connector/ConverterUnity.Geometry.cs @@ -4,13 +4,13 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using Objects.Other; -using Objects.Primitive; using Speckle.ConnectorUnity; using Speckle.Core.Models; using UnityEditor; using UnityEngine; + using Mesh = Objects.Geometry.Mesh; -using Object = UnityEngine.Object; +using SColor = System.Drawing.Color; namespace Objects.Converter.Unity { @@ -57,14 +57,14 @@ namespace Objects.Converter.Unity /// /// /// - public Vector3[] ArrayToPoints(IEnumerable arr, string units) + public Vector3[] ArrayToPoints(IList arr, string units) { - if (arr.Count() % 3 != 0) throw new Exception("Array malformed: length%3 != 0."); + 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); + Vector3[] points = new Vector3[arr.Count / 3]; + + for (int i = 2, k = 0; i < arr.Count; i += 3) + points[k++] = VectorByCoordinates(arr[i - 2], arr[i - 1], arr[i], units); return points; @@ -109,53 +109,62 @@ namespace Objects.Converter.Unity /// - /// Converts a Speckle mesh to a GameObject with a mesh renderer + /// Converts the component on into a Speckle /// - /// - /// + /// The Unity to convert + /// The converted , if no on exists public Mesh MeshToSpeckle(GameObject go) { //TODO: support multiple filters? var filter = go.GetComponent(); - if (filter == null) + if (filter == null) return null; + + var nativeMesh = filter.mesh; + + var nTriangles = nativeMesh.triangles; + List sFaces = new List(nTriangles.Length * 4); + for (int i = 2; i < nTriangles.Length; i += 3) { - return null; + sFaces.Add(0); //Triangle cardinality indicator + + sFaces.Add(nTriangles[i]); + sFaces.Add(nTriangles[i - 1]); + sFaces.Add(nTriangles[i - 2]); } - //convert triangle array into speckleMesh faces - List faces = new List(); - int i = 0; - //store them here, makes it like 1000000x faster? - var triangles = filter.mesh.triangles; - while (i < triangles.Length) + var nVertices = nativeMesh.vertices; + List sVertices = new List(nVertices.Length * 3); + foreach (var vertex in nVertices) { - faces.Add(0); + var p = go.transform.TransformPoint(vertex); + sVertices.Add(p.x); + sVertices.Add(p.y); + sVertices.Add(p.z); + } + + var nColors = nativeMesh.colors; + List sColors = new List(nColors.Length); + sColors.AddRange(nColors.Select(c => c.ToIntColor())); - faces.Add(triangles[i + 0]); - faces.Add(triangles[i + 2]); - faces.Add(triangles[i + 1]); - i += 3; + var nTexCoords = nativeMesh.uv; + List sTexCoords = new List(nTexCoords.Length * 2); + foreach (var uv in nTexCoords) + { + sTexCoords.Add(uv.x); + sTexCoords.Add(uv.y); } 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.vertices = sVertices; + mesh.faces = sFaces; + mesh.colors = sColors; + mesh.textureCoordinates = sTexCoords; 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); - } - - mesh.faces = faces; - return mesh; } #endregion @@ -181,7 +190,7 @@ namespace Objects.Converter.Unity } /// - /// Converts a Speckle point to a GameObject with a line renderer + /// Converts a Speckle to a with a /// /// /// @@ -189,13 +198,13 @@ namespace Objects.Converter.Unity { Vector3 newPt = VectorByCoordinates(point.x, point.y, point.z, point.units); - var go = NewPointBasedGameObject(new Vector3[2] { newPt, newPt }, point.speckle_type); + var go = NewPointBasedGameObject(new Vector3[] { newPt, newPt }, point.speckle_type); return go; } /// - /// Converts a Speckle line to a GameObject with a line renderer + /// Converts a Speckle to a with a /// /// /// @@ -208,31 +217,31 @@ namespace Objects.Converter.Unity } /// - /// Converts a Speckle polyline to a GameObject with a line renderer + /// Converts a Speckle to a with a /// /// /// public GameObject PolylineToNative(Polyline polyline) { - var points = polyline.points.Select(x => VectorFromPoint(x)); + var points = polyline.GetPoints().Select(VectorFromPoint); var go = NewPointBasedGameObject(points.ToArray(), polyline.speckle_type); return go; } /// - /// Converts a Speckle curve to a GameObject with a line renderer + /// Converts a Speckle to a with a /// /// /// public GameObject CurveToNative(Curve curve) { var points = ArrayToPoints(curve.points, curve.units); - var go = NewPointBasedGameObject(points.ToArray(), curve.speckle_type); + var go = NewPointBasedGameObject(points, curve.speckle_type); return go; } - + public GameObject MeshToNative(Base speckleMeshObject) { if (!(speckleMeshObject["displayMesh"] is Mesh)) @@ -242,11 +251,11 @@ namespace Objects.Converter.Unity speckleMeshObject["renderMaterial"] as RenderMaterial, speckleMeshObject.GetMembers()); } /// - /// Converts a Speckle mesh to a GameObject with a mesh renderer + /// Converts to a with a /// /// Mesh to convert - /// If provided will override the renderMaterial on the mesh itself - /// If provided will override the properties on the mesh itself + /// If provided, will override the renderMaterial on the mesh itself + /// If provided, will override the properties on the mesh itself /// public GameObject MeshToNative( Mesh speckleMesh, RenderMaterial renderMaterial = null, @@ -257,10 +266,10 @@ namespace Objects.Converter.Unity { return null; } - + var recenterMeshTransforms = true; //TODO: figure out how best to change this? - + speckleMesh.AlignVerticesWithTexCoordsByIndex(); var verts = ArrayToPoints(speckleMesh.vertices, speckleMesh.units); @@ -270,15 +279,17 @@ namespace Objects.Converter.Unity // TODO: Check if this is causing issues with normals for mesh while (i < speckleMesh.faces.Count) { - if (speckleMesh.faces[i] == 0) + int n = speckleMesh.faces[i]; + if (n < 3) n += 3; // 0 -> 3, 1 - > 4 + + if (n == 3) { //Triangles tris.Add(speckleMesh.faces[i + 1]); tris.Add(speckleMesh.faces[i + 3]); tris.Add(speckleMesh.faces[i + 2]); - i += 4; } - else + else if (n == 4) { //Quads to triangles tris.Add(speckleMesh.faces[i + 1]); @@ -288,12 +299,16 @@ namespace Objects.Converter.Unity tris.Add(speckleMesh.faces[i + 1]); tris.Add(speckleMesh.faces[i + 4]); tris.Add(speckleMesh.faces[i + 3]); - - i += 5; } + else + { + //TODO n-gon triangulation, for now n-gon faces will be ignored + + } + + i += n + 1; } - var go = new GameObject { name = speckleMesh.speckle_type }; var mesh = new UnityEngine.Mesh { name = speckleMesh.speckle_type }; @@ -322,18 +337,37 @@ namespace Objects.Converter.Unity verts[l] -= meshBounds.center; } } - - - - + mesh.SetVertices(verts); mesh.SetTriangles(tris, 0); - if (speckleMesh.bbox != null) + //Set texture coordinates + bool hasValidUVs = speckleMesh.TextureCoordinatesCount == speckleMesh.VerticesCount; + if(speckleMesh.textureCoordinates.Count > 0 && !hasValidUVs) Debug.LogWarning($"Expected number of UV coordinates to equal vertices. Got {speckleMesh.TextureCoordinatesCount} expected {speckleMesh.VerticesCount}. \nID = {speckleMesh.id}", mesh); + + if (hasValidUVs) { + var uv = new List(speckleMesh.TextureCoordinatesCount); + for (int j = 0; j < speckleMesh.TextureCoordinatesCount; j++) + { + var (u, v) = speckleMesh.GetTextureCoordinate(j); + uv.Add(new Vector2((float)u,(float)v)); + } + mesh.SetUVs(0, uv); + } + else if (speckleMesh.bbox != null) + { + //Attempt to generate some crude UV coordinates using bbox var uv = GenerateUV(verts, (float)speckleMesh.bbox.xSize.Length, (float)speckleMesh.bbox.ySize.Length).ToList(); mesh.SetUVs(0, uv); + } + //Set vertex colors + if (speckleMesh.colors.Count == speckleMesh.VerticesCount) + { + static Color ToUnityColor(SColor color) => new Color(color.R, color.G, color.B, color.A); + var colors = speckleMesh.colors.Select(c => ToUnityColor(SColor.FromArgb(c))).ToList(); + mesh.SetColors(colors); } // BUG: causing some funky issues with meshes diff --git a/Assets/Speckle Connector/Core/SpeckleCore2.dll b/Assets/Speckle Connector/Core/SpeckleCore2.dll index aa3c801..ced387d 100644 Binary files a/Assets/Speckle Connector/Core/SpeckleCore2.dll and b/Assets/Speckle Connector/Core/SpeckleCore2.dll differ diff --git a/Assets/Speckle Connector/Objects/Objects.dll b/Assets/Speckle Connector/Objects/Objects.dll index ad3b857..b06c136 100644 Binary files a/Assets/Speckle Connector/Objects/Objects.dll and b/Assets/Speckle Connector/Objects/Objects.dll differ