Browse Source

Added points and lines evaluation

Vicente Penades 6 years ago
parent
commit
54a392b4ed

+ 4 - 0
src/Shared/_Extensions.cs

@@ -485,6 +485,8 @@ namespace SharpGLTF
 
                         break;
                     }
+
+                default: throw new NotImplementedException();
             }
         }
 
@@ -570,6 +572,8 @@ namespace SharpGLTF
 
                         break;
                     }
+
+                default: throw new NotImplementedException();
             }
         }
 

+ 47 - 31
src/SharpGLTF.Toolkit/Geometry/VertexBufferColumns.cs

@@ -236,60 +236,74 @@ namespace SharpGLTF.Geometry
 
         #region API - Vertex indexing
 
+        public Type GetCompatibleVertexType()
+        {
+            var hasNormals = Normals != null;
+            var hasTangents = hasNormals && Tangents != null;
+
+            int numCols = 0;
+            if (Colors0 != null) numCols = 1;
+            if (Colors0 != null && Colors1 != null) numCols = 2;
+
+            int numTexs = 0;
+            if (TexCoords0 != null) numTexs = 1;
+            if (TexCoords0 != null && TexCoords1 != null) numTexs = 2;
+
+            int numJoints = 0;
+            if (Joints0 != null) numJoints = 4;
+            if (Joints0 != null && Joints1 != null) numJoints = 8;
+
+            return VertexUtils.GetVertexBuilderType(hasNormals, hasTangents, numCols, numTexs, numJoints);
+        }
+
         private TvG GetVertexGeometry<TvG>(int index)
             where TvG : struct, IVertexGeometry
         {
-            var v = default(TvG);
+            var g = default(TvG);
 
-            if (Positions != null) v.SetPosition(Positions[index]);
-            if (Normals != null) v.SetNormal(Normals[index]);
-            if (Tangents != null) v.SetTangent(Tangents[index]);
+            if (Positions != null) g.SetPosition(Positions[index]);
+            if (Normals != null) g.SetNormal(Normals[index]);
+            if (Tangents != null) g.SetTangent(Tangents[index]);
 
-            return v;
+            return g;
         }
 
         private TvM GetVertexMaterial<TvM>(int index)
             where TvM : struct, IVertexMaterial
         {
-            var v = default(TvM);
+            var m = default(TvM);
 
-            if (Colors0 != null && v.MaxColors > 0) v.SetColor(0, Colors0[index]);
-            if (Colors1 != null && v.MaxColors > 1) v.SetColor(1, Colors1[index]);
+            if (Colors0 != null && m.MaxColors > 0) m.SetColor(0, Colors0[index]);
+            if (Colors1 != null && m.MaxColors > 1) m.SetColor(1, Colors1[index]);
 
-            if (TexCoords0 != null && v.MaxTextCoords > 0) v.SetTexCoord(0, TexCoords0[index]);
-            if (TexCoords1 != null && v.MaxTextCoords > 1) v.SetTexCoord(1, TexCoords1[index]);
+            if (TexCoords0 != null && m.MaxTextCoords > 0) m.SetTexCoord(0, TexCoords0[index]);
+            if (TexCoords1 != null && m.MaxTextCoords > 1) m.SetTexCoord(1, TexCoords1[index]);
 
-            return v;
+            return m;
         }
 
         private TvS GetVertexSkinning<TvS>(int index)
             where TvS : struct, IVertexSkinning
         {
-            IVertexSkinning v = default(VertexTypes.VertexJoints16x8);
+            var s = default(TvS);
 
-            if (Joints0 != null && Weights0 != null)
-            {
-                var j = Joints0[index];
-                var w = Weights0[index];
+            if (s.MaxBindings == 0) return s;
 
-                v.SetJointBinding(0, (int)j.X, w.X);
-                v.SetJointBinding(1, (int)j.Y, w.Y);
-                v.SetJointBinding(2, (int)j.Z, w.Z);
-                v.SetJointBinding(3, (int)j.W, w.W);
-            }
-
-            if (Joints1 != null && Weights1 != null)
+            if (Joints0 != null && Weights0 != null)
             {
-                var j = Joints1[index];
-                var w = Weights1[index];
-
-                v.SetJointBinding(4, (int)j.X, w.X);
-                v.SetJointBinding(5, (int)j.Y, w.Y);
-                v.SetJointBinding(6, (int)j.Z, w.Z);
-                v.SetJointBinding(7, (int)j.W, w.W);
+                if (Joints1 != null && Weights1 != null)
+                {
+                    var sparse = new Transforms.SparseWeight8(Joints0[index], Joints1[index], Weights0[index], Weights1[index]);
+                    s.SetWeights(sparse);
+                }
+                else
+                {
+                    var sparse = new Transforms.SparseWeight8(Joints0[index], Weights0[index]);
+                    s.SetWeights(sparse);
+                }
             }
 
-            return VertexUtils.ConvertToSkinning<TvS>(v);
+            return s;
         }
 
         public IVertexBuilder GetVertex(Type vertexType, int index)
@@ -299,9 +313,11 @@ namespace SharpGLTF.Geometry
             var s = GetVertexSkinning<VertexJoints16x8>(index);
 
             var v = (IVertexBuilder)Activator.CreateInstance(vertexType);
+
             v.SetGeometry(g);
             v.SetMaterial(m);
             v.SetSkinning(s);
+
             return v;
         }
 

+ 22 - 0
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexUtils.cs

@@ -31,6 +31,11 @@ namespace SharpGLTF.Geometry.VertexTypes
             uvcoords = vertexAttributes.Contains("TEXCOORD_2") ? 3 : uvcoords;
             uvcoords = vertexAttributes.Contains("TEXCOORD_3") ? 4 : uvcoords;
 
+            return GetVertexMaterialType(colors, uvcoords);
+        }
+
+        public static Type GetVertexMaterialType(int colors, int uvcoords)
+        {
             if (colors == 0)
             {
                 if (uvcoords == 0) return typeof(VertexEmpty);
@@ -77,6 +82,23 @@ namespace SharpGLTF.Geometry.VertexTypes
             return vtype.MakeGenericType(tvg, tvm, tvs);
         }
 
+        public static Type GetVertexBuilderType(bool hasNormals, bool hasTangents, int numCols, int numUV, int numJoints)
+        {
+            var tvg = typeof(VertexPosition);
+            if (hasNormals) tvg = typeof(VertexPositionNormal);
+            if (hasTangents) tvg = typeof(VertexPositionNormalTangent);
+
+            var tvm = GetVertexMaterialType(numCols, numUV);
+
+            var tvs = typeof(VertexEmpty);
+            if (numJoints == 4) tvs = typeof(VertexJoints16x4);
+            if (numJoints >= 8) tvs = typeof(VertexJoints16x8);
+
+            var vtype = typeof(VertexBuilder<,,>);
+
+            return vtype.MakeGenericType(tvg, tvm, tvs);
+        }
+
         public static bool SanitizeVertex<TvG>(this TvG inVertex, out TvG outVertex)
             where TvG : struct, IVertexGeometry
         {

+ 146 - 43
src/SharpGLTF.Toolkit/Schema2/MeshExtensions.cs

@@ -8,6 +8,8 @@ using SharpGLTF.Memory;
 using SharpGLTF.Geometry;
 using SharpGLTF.Geometry.VertexTypes;
 
+using MESHXFORM = SharpGLTF.Transforms.ITransform;
+
 namespace SharpGLTF.Schema2
 {
     public static partial class Schema2Toolkit
@@ -257,23 +259,79 @@ namespace SharpGLTF.Schema2
 
         #region evaluation
 
-        public static IEnumerable<(IVertexBuilder, IVertexBuilder, IVertexBuilder, Material)> EvaluateTriangles(this Mesh mesh)
+        public static IEnumerable<(IVertexBuilder, Material)> EvaluatePoints(this Mesh mesh, MESHXFORM xform = null)
+        {
+            if (mesh == null) return Enumerable.Empty<(IVertexBuilder, Material)>();
+
+            return mesh.Primitives.SelectMany(item => item.EvaluatePoints(xform));
+        }
+
+        public static IEnumerable<(IVertexBuilder, Material)> EvaluatePoints(this MeshPrimitive prim, MESHXFORM xform = null)
+        {
+            if (prim == null) yield break;
+            if (xform != null && !xform.Visible) yield break;
+
+            var points = prim.GetPointIndices();
+            if (!points.Any()) yield break;
+
+            var vertices = prim.GetVertexColumns(xform);
+
+            var vtype = vertices.GetCompatibleVertexType();
+
+            foreach (var t in points)
+            {
+                var a = vertices.GetVertex(vtype, t);
+
+                yield return (a, prim.Material);
+            }
+        }
+
+        public static IEnumerable<(IVertexBuilder, IVertexBuilder, Material)> EvaluateLines(this Mesh mesh, MESHXFORM xform = null)
+        {
+            if (mesh == null) return Enumerable.Empty<(IVertexBuilder, IVertexBuilder, Material)>();
+
+            return mesh.Primitives.SelectMany(item => item.EvaluateLines(xform));
+        }
+
+        public static IEnumerable<(IVertexBuilder, IVertexBuilder, Material)> EvaluateLines(this MeshPrimitive prim, MESHXFORM xform = null)
+        {
+            if (prim == null) yield break;
+            if (xform != null && !xform.Visible) yield break;
+
+            var lines = prim.GetLineIndices();
+            if (!lines.Any()) yield break;
+
+            var vertices = prim.GetVertexColumns(xform);
+
+            var vtype = vertices.GetCompatibleVertexType();
+
+            foreach (var t in lines)
+            {
+                var a = vertices.GetVertex(vtype, t.Item1);
+                var b = vertices.GetVertex(vtype, t.Item2);
+
+                yield return (a, b, prim.Material);
+            }
+        }
+
+        public static IEnumerable<(IVertexBuilder, IVertexBuilder, IVertexBuilder, Material)> EvaluateTriangles(this Mesh mesh, MESHXFORM xform = null)
         {
             if (mesh == null) return Enumerable.Empty<(IVertexBuilder, IVertexBuilder, IVertexBuilder, Material)>();
 
-            return mesh.Primitives.SelectMany(item => item.EvaluateTriangles());
+            return mesh.Primitives.SelectMany(item => item.EvaluateTriangles(xform));
         }
 
-        public static IEnumerable<(IVertexBuilder, IVertexBuilder, IVertexBuilder, Material)> EvaluateTriangles(this MeshPrimitive prim)
+        public static IEnumerable<(IVertexBuilder, IVertexBuilder, IVertexBuilder, Material)> EvaluateTriangles(this MeshPrimitive prim, MESHXFORM xform = null)
         {
             if (prim == null) yield break;
+            if (xform != null && !xform.Visible) yield break;
 
-            var vertices = prim.GetVertexColumns();
             var triangles = prim.GetTriangleIndices();
+            if (!triangles.Any()) yield break;
 
-            bool hasNormals = vertices.Normals != null;
+            var vertices = prim.GetVertexColumns(xform);
 
-            var vtype = VertexUtils.GetVertexBuilderType(prim.VertexAccessors.Keys.ToArray());
+            var vtype = vertices.GetCompatibleVertexType();
 
             foreach (var t in triangles)
             {
@@ -281,16 +339,6 @@ namespace SharpGLTF.Schema2
                 var b = vertices.GetVertex(vtype, t.Item2);
                 var c = vertices.GetVertex(vtype, t.Item3);
 
-                /*
-                if (!hasNormals)
-                {
-                    var n = Vector3.Cross(b.Position - a.Position, c.Position - a.Position);
-                    n = Vector3.Normalize(n);
-                    a.Geometry.SetNormal(n);
-                    b.Geometry.SetNormal(n);
-                    c.Geometry.SetNormal(n);
-                }*/
-
                 yield return (a, b, c, prim.Material);
             }
         }
@@ -336,7 +384,7 @@ namespace SharpGLTF.Schema2
             }
         }
 
-        public static IEnumerable<(VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>, Material)> EvaluateTriangles<TvG, TvM>(this Mesh mesh, Transforms.ITransform xform)
+        public static IEnumerable<(VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>, Material)> EvaluateTriangles<TvG, TvM>(this Mesh mesh, MESHXFORM xform)
             where TvG : struct, IVertexGeometry
             where TvM : struct, IVertexMaterial
         {
@@ -345,20 +393,16 @@ namespace SharpGLTF.Schema2
             return mesh.Primitives.SelectMany(item => item.EvaluateTriangles<TvG, TvM>(xform));
         }
 
-        public static IEnumerable<(VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>, Material)> EvaluateTriangles<TvG, TvM>(this MeshPrimitive prim, Transforms.ITransform xform)
+        public static IEnumerable<(VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>, Material)> EvaluateTriangles<TvG, TvM>(this MeshPrimitive prim, MESHXFORM xform)
             where TvG : struct, IVertexGeometry
             where TvM : struct, IVertexMaterial
         {
+            if (prim == null) yield break;
             if (xform == null || !xform.Visible) yield break;
 
-            var vertices = prim.GetVertexColumns();
-
-            vertices.ApplyTransform(xform);
-
+            var vertices = prim.GetVertexColumns(xform);
             var triangles = prim.GetTriangleIndices();
 
-            var jointweights = new (int, float)[8];
-
             foreach (var t in triangles)
             {
                 var a = vertices.GetVertex<TvG, TvM>(t.Item1);
@@ -369,7 +413,53 @@ namespace SharpGLTF.Schema2
             }
         }
 
-        public static VertexBufferColumns GetVertexColumns(this MeshPrimitive primitive)
+        public static IEnumerable<int> GetPointIndices(this MeshPrimitive primitive)
+        {
+            if (primitive == null || primitive.DrawPrimitiveType.GetPrimitiveVertexSize() != 1) return Enumerable.Empty<int>();
+
+            if (primitive.IndexAccessor == null) return Enumerable.Range(0, primitive.GetVertexAccessor("POSITION").Count);
+
+            return primitive.IndexAccessor.AsIndicesArray().Select(item => (int)item);
+        }
+
+        public static IEnumerable<(int, int)> GetLineIndices(this MeshPrimitive primitive)
+        {
+            if (primitive == null || primitive.DrawPrimitiveType.GetPrimitiveVertexSize() != 2) return Enumerable.Empty<(int, int)>();
+
+            if (primitive.IndexAccessor == null) return primitive.DrawPrimitiveType.GetLinesIndices(primitive.GetVertexAccessor("POSITION").Count);
+
+            return primitive.DrawPrimitiveType.GetLinesIndices(primitive.IndexAccessor.AsIndicesArray());
+        }
+
+        public static IEnumerable<(int, int, int)> GetTriangleIndices(this MeshPrimitive primitive)
+        {
+            if (primitive == null || primitive.DrawPrimitiveType.GetPrimitiveVertexSize() != 3) return Enumerable.Empty<(int, int, int)>();
+
+            if (primitive.IndexAccessor == null) return primitive.DrawPrimitiveType.GetTrianglesIndices(primitive.GetVertexAccessor("POSITION").Count);
+
+            return primitive.DrawPrimitiveType.GetTrianglesIndices(primitive.IndexAccessor.AsIndicesArray());
+        }
+
+        public static int GetPrimitiveVertexSize(this PrimitiveType ptype)
+        {
+            switch (ptype)
+            {
+                case PrimitiveType.POINTS: return 1;
+                case PrimitiveType.LINES: return 2;
+                case PrimitiveType.LINE_LOOP: return 2;
+                case PrimitiveType.LINE_STRIP: return 2;
+                case PrimitiveType.TRIANGLES: return 3;
+                case PrimitiveType.TRIANGLE_FAN: return 3;
+                case PrimitiveType.TRIANGLE_STRIP: return 3;
+                default: throw new NotImplementedException();
+            }
+        }
+
+        #endregion
+
+        #region mesh conversion
+
+        public static VertexBufferColumns GetVertexColumns(this MeshPrimitive primitive, MESHXFORM xform = null)
         {
             Guard.NotNull(primitive, nameof(primitive));
 
@@ -383,6 +473,8 @@ namespace SharpGLTF.Schema2
                 _Initialize(morphTarget, columns.AddMorphTarget());
             }
 
+            if (xform != null) columns.ApplyTransform(xform);
+
             return columns;
         }
 
@@ -414,15 +506,6 @@ namespace SharpGLTF.Schema2
             if (vertexAccessors.ContainsKey("COLOR_0")) dstColumns.Colors0 = vertexAccessors["COLOR_0"].AsVector4Array();
         }
 
-        public static IEnumerable<(int, int, int)> GetTriangleIndices(this MeshPrimitive primitive)
-        {
-            if (primitive == null) return Enumerable.Empty<(int, int, int)>();
-
-            if (primitive.IndexAccessor == null) return primitive.DrawPrimitiveType.GetTrianglesIndices(primitive.GetVertexAccessor("POSITION").Count);
-
-            return primitive.DrawPrimitiveType.GetTrianglesIndices(primitive.IndexAccessor.AsIndicesArray());
-        }
-
         /// <summary>
         /// Calculates a default set of normals for the given mesh.
         /// </summary>
@@ -430,6 +513,8 @@ namespace SharpGLTF.Schema2
         /// <returns>A <see cref="Dictionary{TKey, TValue}"/> where the keys represent positions and the values represent Normals.</returns>
         public static Dictionary<Vector3, Vector3> GetComputedNormals(this Mesh mesh)
         {
+            if (mesh == null) return null;
+
             var posnrm = new Dictionary<Vector3, Vector3>();
 
             void addDirection(Dictionary<Vector3, Vector3> dict, Vector3 pos, Vector3 dir)
@@ -553,31 +638,49 @@ namespace SharpGLTF.Schema2
 
             Materials.MaterialBuilder defMat = null;
 
-            var dstMaterials = new Dictionary<Material, Materials.MaterialBuilder>();
-
             var dstMesh = MeshBuilderToolkit.CreateMeshBuilderFromVertexAttributes<Materials.MaterialBuilder>(vertexAttributes);
 
-            foreach (var srcTri in srcMesh.EvaluateTriangles())
+            var dstMaterials = new Dictionary<Material, Materials.MaterialBuilder>();
+
+            IPrimitiveBuilder GetPrimitive(Material srcMaterial, int vcount)
             {
                 IPrimitiveBuilder dstPrim = null;
 
-                if (srcTri.Item4 == null)
+                if (srcMaterial == null)
                 {
                     if (defMat == null) defMat = Materials.MaterialBuilder.CreateDefault();
-                    dstPrim = dstMesh.UsePrimitive(defMat);
+                    dstPrim = dstMesh.UsePrimitive(defMat, vcount);
                 }
                 else
                 {
-                    if (!dstMaterials.TryGetValue(srcTri.Item4, out Materials.MaterialBuilder dstMat))
+                    if (!dstMaterials.TryGetValue(srcMaterial, out Materials.MaterialBuilder dstMat))
                     {
                         dstMat = new Materials.MaterialBuilder();
-                        srcTri.Item4.CopyTo(dstMat);
-                        dstMaterials[srcTri.Item4] = dstMat;
+                        srcMaterial.CopyTo(dstMat);
+                        dstMaterials[srcMaterial] = dstMat;
                     }
 
-                    dstPrim = dstMesh.UsePrimitive(dstMat);
+                    dstPrim = dstMesh.UsePrimitive(dstMat, vcount);
                 }
 
+                return dstPrim;
+            }
+
+            foreach (var srcTri in srcMesh.EvaluatePoints())
+            {
+                var dstPrim = GetPrimitive(srcTri.Item2, 1);
+                dstPrim.AddPoint(srcTri.Item1);
+            }
+
+            foreach (var srcTri in srcMesh.EvaluateLines())
+            {
+                var dstPrim = GetPrimitive(srcTri.Item3, 2);
+                dstPrim.AddLine(srcTri.Item1,srcTri.Item2);
+            }
+
+            foreach (var srcTri in srcMesh.EvaluateTriangles())
+            {
+                var dstPrim = GetPrimitive(srcTri.Item4, 3);
                 dstPrim.AddTriangle(srcTri.Item1, srcTri.Item2, srcTri.Item3);
             }
 

+ 32 - 0
src/SharpGLTF.Toolkit/Schema2/SceneExtensions.cs

@@ -202,6 +202,38 @@ namespace SharpGLTF.Schema2
             return null;
         }
 
+        /// <summary>
+        /// Yields a collection of triangles representing the geometry in world space.
+        /// </summary>
+        /// /// <param name="scene">A <see cref="Scene"/> instance.</param>
+        /// <param name="animation">An <see cref="Animation"/> instance, or null.</param>
+        /// <param name="time">The animation time.</param>
+        /// <returns>A collection of triangles in world space.</returns>
+        public static IEnumerable<(IVertexBuilder, IVertexBuilder, IVertexBuilder, Material)> EvaluateTriangles(this Scene scene, Animation animation = null, float time = 0)
+        {
+            return Node
+                .Flatten(scene)
+                .SelectMany(item => item.EvaluateTriangles(animation, time));
+        }
+
+        /// <summary>
+        /// Yields a collection of triangles representing the geometry in world space.
+        /// </summary>
+        /// <param name="node">A <see cref="Node"/> instance.</param>
+        /// <param name="animation">An <see cref="Animation"/> instance, or null.</param>
+        /// <param name="time">The animation time.</param>
+        /// <returns>A collection of triangles in world space.</returns>
+        public static IEnumerable<(IVertexBuilder, IVertexBuilder, IVertexBuilder, Material)> EvaluateTriangles(this Node node, Animation animation = null, float time = 0)
+        {
+            var mesh = node?.Mesh;
+
+            if (node == null || mesh == null) return Enumerable.Empty<(IVertexBuilder, IVertexBuilder, IVertexBuilder, Material)>();
+
+            var xform = node.GetMeshWorldTransform(animation, time);
+
+            return mesh.EvaluateTriangles(xform);
+        }
+
         /// <summary>
         /// Yields a collection of triangles representing the geometry in world space.
         /// </summary>