2
0
Эх сурвалжийг харах

added more examples of mesh creation

Vicente Penades 6 жил өмнө
parent
commit
da5521de75

+ 29 - 0
src/SharpGLTF.DOM/Geometry/MemoryAccessor.cs

@@ -110,6 +110,35 @@ namespace SharpGLTF.Geometry
             }
         }
 
+        public static int SetInterleavedInfo(MemoryAccessInfo[] attributes, int byteOffset, int itemsCount)
+        {
+            var byteStride = 0;
+
+            for (int i = 0; i < attributes.Length; ++i)
+            {
+                var a = attributes[i];
+
+                a.ByteOffset = byteOffset;
+                a.ItemsCount = itemsCount;
+
+                var attributeStride = a.ByteLength;
+
+                byteStride += attributeStride;
+                byteOffset += attributeStride;
+
+                attributes[i] = a;
+            }
+
+            for (int i = 0; i < attributes.Length; ++i)
+            {
+                var a = attributes[i];
+                a.ByteStride = byteStride;
+                attributes[i] = a;
+            }
+
+            return byteStride;
+        }
+
         #endregion
     }
 

+ 47 - 1
tests/SharpGLTF.Tests/Schema2/Authoring/CreateModelTests.cs

@@ -140,7 +140,7 @@ namespace SharpGLTF.Schema2.Authoring
         }
 
         [Test(Description = "Creates a simple scene using a mesh builder helper class")]
-        public void CreateMeshBuilderScene()
+        public void CreateSimpleMeshBuilderScene()
         {
             TestContext.CurrentContext.AttachShowDirLink();
             TestContext.CurrentContext.AttachGltfValidatorLink();
@@ -168,5 +168,51 @@ namespace SharpGLTF.Schema2.Authoring
             model.AttachToCurrentTest("result.glb");
             model.AttachToCurrentTest("result.gltf");
         }
+
+
+        struct myVertex
+        {
+            public myVertex(float px, float py, float pz, float nx, float ny, float nz)
+            {
+                Position = new Vector3(px, py, pz);
+                Normal = Vector3.Normalize(new Vector3(nx, ny, nz));
+            }
+
+            public Vector3 Position;
+            public Vector3 Normal;
+        }
+
+        [Test(Description = "Creates an interleaved scene using a mesh builder helper class")]
+        public void CreateInterleavedMeshBuilderScene()
+        {
+            TestContext.CurrentContext.AttachShowDirLink();
+            TestContext.CurrentContext.AttachGltfValidatorLink();
+
+            var meshBuilder = new InterleavedMeshBuilder<myVertex, Vector4>();
+
+            var v1 = new myVertex(-10, 10, 0, -10, 10, 15);
+            var v2 = new myVertex( 10, 10, 0, 10, 10, 15);
+            var v3 = new myVertex( 10,-10, 0, 10, -10, 15);
+            var v4 = new myVertex(-10,-10, 0, -10, -10, 15);            
+            meshBuilder.AddPolygon(new Vector4(1, 1, 1, 1), v1, v2, v3, v4);
+
+            var model = ModelRoot.CreateModel();
+            var scene = model.UseScene("Default");
+            var rnode = scene.CreateNode("RootNode");
+
+            // setup a lambda function that creates a material for a given color
+            Material createMaterialForColor(Vector4 color)
+            {
+                var material = model.CreateMaterial().WithDefault(color);
+                material.DoubleSided = true;
+                return material;
+            };
+
+            // fill our node with the mesh
+            meshBuilder.CopyToNode(rnode, createMaterialForColor);
+
+            model.AttachToCurrentTest("result.glb");
+            model.AttachToCurrentTest("result.gltf");
+        }
     }
 }

+ 187 - 0
tests/SharpGLTF.Tests/Schema2/Authoring/InterleavedMeshBuilder.cs

@@ -0,0 +1,187 @@
+using System;
+using System.Collections.Generic;
+using System.Numerics;
+using System.Text;
+
+namespace SharpGLTF.Schema2.Authoring
+{
+    class InterleavedMeshBuilder<TVertex, TMaterial> where TVertex : struct
+    {
+        #region data
+
+        private readonly VertexColumn<TVertex> _Vertices = new VertexColumn<TVertex>();
+        private readonly Dictionary<TMaterial, List<int>> _Indices = new Dictionary<TMaterial, List<int>>();
+
+        #endregion
+
+        #region API
+
+        public void AddPolygon(TMaterial material, params TVertex[] points)
+        {
+            for (int i = 2; i < points.Length; ++i)
+            {
+                AddTriangle(material, points[0], points[i - 1], points[i]);
+            }
+        }
+
+        public void AddTriangle(TMaterial material, TVertex a, TVertex b, TVertex c)
+        {
+            var aa = _Vertices.Use(a);
+            var bb = _Vertices.Use(b);
+            var cc = _Vertices.Use(c);
+
+            // check for degenerated triangles:
+            if (aa == bb) return;
+            if (aa == cc) return;
+            if (bb == cc) return;
+
+            if (!_Indices.TryGetValue(material, out List<int> indices))
+            {
+                indices = new List<int>();
+                _Indices[material] = indices;
+            }
+
+            indices.Add(aa);
+            indices.Add(bb);
+            indices.Add(cc);
+        }        
+
+        public void CopyToNode(Node dstNode, Func<TMaterial, Material> materialEvaluator)
+        {
+            dstNode.Mesh = dstNode.LogicalParent.CreateMesh();
+            CopyToMesh(dstNode.Mesh, materialEvaluator);
+        }
+
+        public void CopyToMesh(Mesh dstMesh, Func<TMaterial, Material> materialEvaluator)
+        {
+            var root = dstMesh.LogicalParent;
+
+            // get vertex attributes from TVertex type using reflection
+            var attributes = _GetVertexAttributes(_Vertices.Count);
+
+            // create vertex buffer
+            int byteStride = attributes[0].ByteStride;
+            var vbuffer = root.UseBufferView(new Byte[byteStride * _Vertices.Count], byteStride, BufferMode.ARRAY_BUFFER);
+
+            // create vertex accessors
+            var vertexAccessors = new Dictionary<String, Accessor>();
+
+            foreach(var attribute in attributes)
+            {
+                var accessor = root.CreateAccessor(attribute.Name);
+
+                var attributeType = _GetVertexAttributeType(attribute.Name);
+
+                if (attributeType == typeof(Vector2)) accessor.WithVertexData(vbuffer, attribute.ByteOffset, _GetVector2Column(_Vertices, attribute.Name), attribute.Encoding, attribute.Normalized);
+                if (attributeType == typeof(Vector3)) accessor.WithVertexData(vbuffer, attribute.ByteOffset, _GetVector3Column(_Vertices, attribute.Name), attribute.Encoding, attribute.Normalized);
+                if (attributeType == typeof(Vector4)) accessor.WithVertexData(vbuffer, attribute.ByteOffset, _GetVector4Column(_Vertices, attribute.Name), attribute.Encoding, attribute.Normalized);
+
+                vertexAccessors[attribute.Name.ToUpper()] = accessor;
+            }            
+
+            foreach (var kvp in _Indices)
+            {
+                // create index buffer
+                var ibuffer = root.UseBufferView(new Byte[4 * kvp.Value.Count], 0, BufferMode.ELEMENT_ARRAY_BUFFER);
+
+                var indices = root
+                    .CreateAccessor("Indices")
+                    .WithIndexData(ibuffer, 0, kvp.Value);
+
+                // create mesh primitive
+                var prim = dstMesh.CreatePrimitive();
+                foreach (var va in vertexAccessors) prim.SetVertexAccessor(va.Key, va.Value);
+                prim.SetIndexAccessor(indices);
+                prim.DrawPrimitiveType = PrimitiveType.TRIANGLES;
+
+                prim.Material = materialEvaluator(kvp.Key);
+            }
+
+            root.MergeBuffers();
+        }
+
+        #endregion
+
+        #region core
+
+        private Geometry.MemoryAccessInfo[] _GetVertexAttributes(int itemsCount)
+        {
+            var type = typeof(TVertex);
+
+            var attributes = new List<Geometry.MemoryAccessInfo>();
+
+            foreach (var field in type.GetFields())
+            {
+                var attributeName = field.Name;
+                var attributeInfo = Geometry.MemoryAccessInfo.CreateDefaultElement(attributeName.ToUpper());
+                attributes.Add(attributeInfo);
+            }
+
+            var array = attributes.ToArray();
+
+            Geometry.MemoryAccessInfo.SetInterleavedInfo(array, 0, itemsCount);
+
+            return array;
+        }
+
+        private static System.Reflection.FieldInfo _GetVertexField(string fieldName)
+        {
+            foreach (var field in typeof(TVertex).GetFields())
+            {
+                if (field.Name.ToLower() == fieldName.ToLower()) return field;
+            }
+
+            return null;
+        }
+
+        private static Type _GetVertexAttributeType(string fieldName)
+        {
+            return _GetVertexField(fieldName).FieldType;
+        }
+
+        private static Vector2[] _GetVector2Column(IReadOnlyList<TVertex> vertices, string fieldName)
+        {
+            var dst = new Vector2[vertices.Count];
+
+            var finfo = _GetVertexField(fieldName);
+
+            for (int i = 0; i < dst.Length; ++i)
+            {
+                dst[i] = (Vector2)finfo.GetValue(vertices[i]);
+            }
+
+            return dst;
+        }
+
+        private static Vector3[] _GetVector3Column(IReadOnlyList<TVertex> vertices, string fieldName)
+        {
+            var dst = new Vector3[vertices.Count];
+
+            var finfo = _GetVertexField(fieldName);
+
+            for (int i = 0; i < dst.Length; ++i)
+            {
+                dst[i] = (Vector3)finfo.GetValue(vertices[i]);
+            }
+
+            return dst;
+        }
+
+        private static Vector4[] _GetVector4Column(IReadOnlyList<TVertex> vertices, string fieldName)
+        {
+            var dst = new Vector4[vertices.Count];
+
+            var finfo = _GetVertexField(fieldName);
+
+            for (int i = 0; i < dst.Length; ++i)
+            {
+                dst[i] = (Vector4)finfo.GetValue(vertices[i]);
+            }
+
+            return dst;
+        }
+
+        #endregion
+
+    }
+}

+ 4 - 8
tests/SharpGLTF.Tests/Schema2/Authoring/SimpleMeshBuilder.cs

@@ -58,7 +58,7 @@ namespace SharpGLTF.Schema2.Authoring
         {
             dstNode.Mesh = dstNode.LogicalParent.CreateMesh();
             CopyToMesh(dstNode.Mesh, materialEvaluator);
-        }
+        }        
 
         public void CopyToMesh(Mesh dstMesh, Func<TMaterial,Material> materialEvaluator)
         {
@@ -67,24 +67,20 @@ namespace SharpGLTF.Schema2.Authoring
             // create vertex buffer
             const int byteStride = 12 * 2;
 
-            var vbuffer = root.UseBufferView(new Byte[byteStride * _Positions.Count], byteStride, Schema2.BufferMode.ARRAY_BUFFER);
+            var vbuffer = root.UseBufferView(new Byte[byteStride * _Positions.Count], byteStride, BufferMode.ARRAY_BUFFER);
 
             var positions = root
                 .CreateAccessor("Positions")
                 .WithVertexData(vbuffer, 0, _Positions);
 
-            var ppp = positions.AsVector3Array();
-
             var normals = root
                 .CreateAccessor("Normals")
-                .WithVertexData(vbuffer, 12, _CalculateNormals());
-
-            var nnn = normals.AsVector3Array();            
+                .WithVertexData(vbuffer, 12, _CalculateNormals());            
 
             foreach (var kvp in _Indices)
             {
                 // create index buffer
-                var ibuffer = root.UseBufferView(new Byte[4 * kvp.Value.Count], 0, Schema2.BufferMode.ELEMENT_ARRAY_BUFFER);
+                var ibuffer = root.UseBufferView(new Byte[4 * kvp.Value.Count], 0, BufferMode.ELEMENT_ARRAY_BUFFER);
 
                 var indices = root
                     .CreateAccessor("Indices")

+ 1 - 1
tests/SharpGLTF.Tests/WavefrontWriter.cs

@@ -10,7 +10,7 @@ namespace SharpGLTF
 {
 
     class VertexColumn<T> : IReadOnlyList<T>
-        where T:IEquatable<T>
+        where T:struct
     {
         #region data