Quellcode durchsuchen

improving API to creating meshes

Vicente Penades vor 6 Jahren
Ursprung
Commit
40946587db

+ 3 - 3
src/glTF2Sharp.CodeGen/glTF2Sharp.CodeGen.csproj

@@ -7,9 +7,9 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="LibGit2Sharp" Version="0.25.4" />
-    <PackageReference Include="NJsonSchema.CodeGeneration" Version="9.13.17" />
-    <PackageReference Include="NJsonSchema.CodeGeneration.CSharp" Version="9.13.17" />
+    <PackageReference Include="LibGit2Sharp" Version="0.26.0" />
+    <PackageReference Include="NJsonSchema.CodeGeneration" Version="9.13.18" />
+    <PackageReference Include="NJsonSchema.CodeGeneration.CSharp" Version="9.13.18" />
   </ItemGroup>
 
 </Project>

+ 44 - 11
src/glTF2Sharp.DOM/Geometry/MeshPrimitive.cs

@@ -181,7 +181,7 @@ namespace glTF2Sharp.Geometry
             return _MemoryAccessor.AsIntegerArray();
         }
 
-        public void AssignTo(Schema2.MeshPrimitive dstPrim)
+        public void AssignToSchema(Schema2.MeshPrimitive dstPrim)
         {
             var dstAccessor = dstPrim.LogicalParent.LogicalParent.CreateAccessor(this.Name);
             dstAccessor.SetIndexData(_MemoryAccessor);
@@ -195,9 +195,10 @@ namespace glTF2Sharp.Geometry
     {
         #region lifecycle
 
-        public MeshPrimitive() { }
+        internal MeshPrimitive(Mesh owner) { _Owner = owner; }
 
-        public MeshPrimitive(Schema2.MeshPrimitive primitive)
+        internal MeshPrimitive(Mesh owner, Schema2.MeshPrimitive primitive)
+            : this(owner)
         {
             _Vertices = primitive.VertexAccessors
                 .Select(kvp => new VertexAccessor(kvp.Key, kvp.Value))
@@ -213,7 +214,7 @@ namespace glTF2Sharp.Geometry
             }
 
             _Indices = primitive.IndexAccessor == null ? null : new IndicesAccessor(primitive.IndexAccessor);
-            _Primitive = primitive.DrawPrimitiveType;
+            _PrimitiveDrawType = primitive.DrawPrimitiveType;
             _MaterialIndex = primitive.Material?.LogicalIndex;
         }
 
@@ -221,11 +222,14 @@ namespace glTF2Sharp.Geometry
 
         #region data
 
+        private readonly Mesh _Owner;
+
         private VertexAccessor[] _Vertices;
         private readonly List<VertexAccessor[]> _MorphAccessors = new List<VertexAccessor[]>();
 
         private IndicesAccessor _Indices;
-        private Schema2.PrimitiveType _Primitive;
+
+        private Schema2.PrimitiveType _PrimitiveDrawType;
 
         private int? _MaterialIndex;
 
@@ -241,17 +245,18 @@ namespace glTF2Sharp.Geometry
 
         #region API
 
-        public void SetVertices(int itemsCount, params string[] attributes)
+        public void AllocateVertices(int itemsCount, params string[] attributes)
         {
             _Vertices = VertexAccessor.CreateAccessors(itemsCount, attributes);
         }
 
-        public void SetIndices(int itemsCount)
+        public void AllocateIndices(int itemsCount, Schema2.PrimitiveType primitiveType)
         {
+            _PrimitiveDrawType = primitiveType;
             _Indices = IndicesAccessor.CreateAccessors(itemsCount);
         }
 
-        public void AssignTo(Schema2.MeshPrimitive dstPrim)
+        public void AssignToSchema(Schema2.MeshPrimitive dstPrim)
         {
             // TODO: clear primitive
 
@@ -260,9 +265,9 @@ namespace glTF2Sharp.Geometry
                 va.AssignTo(dstPrim);
             }
 
-            if (this._Indices != null) this._Indices.AssignTo(dstPrim);
+            if (this._Indices != null) this._Indices.AssignToSchema(dstPrim);
 
-            dstPrim.DrawPrimitiveType = this._Primitive;
+            dstPrim.DrawPrimitiveType = this._PrimitiveDrawType;
         }
 
         #endregion
@@ -273,6 +278,8 @@ namespace glTF2Sharp.Geometry
     {
         #region lifecycle
 
+        public Mesh() { }
+
         public static Mesh[] Create(IReadOnlyList<Schema2.Mesh> src)
         {
             var dst = new Mesh[src.Count];
@@ -288,7 +295,7 @@ namespace glTF2Sharp.Geometry
         public Mesh(Schema2.Mesh mesh)
             : base(mesh)
         {
-            _Primitives.AddRange(mesh.Primitives, item => new MeshPrimitive(item));
+            _Primitives.AddRange(mesh.Primitives, item => new MeshPrimitive(this, item));
             _MorpthWeights.AddRange(mesh.MorphWeights);
         }
 
@@ -300,5 +307,31 @@ namespace glTF2Sharp.Geometry
         private readonly List<Single> _MorpthWeights = new List<float>();
 
         #endregion
+
+        #region API
+
+        public MeshPrimitive CreatePrimitive()
+        {
+            var p = new MeshPrimitive(this);
+            _Primitives.Add(p);
+
+            return p;
+        }
+
+        public void AssignToSchema(Schema2.Mesh mesh)
+        {
+            mesh.Name = this.Name;
+
+            foreach (var srcp in this._Primitives)
+            {
+                var dstp = mesh.CreatePrimitive();
+
+                srcp.AssignToSchema(dstp);
+            }
+
+            // todo: set morph targets
+        }
+
+        #endregion
     }
 }

+ 16 - 13
src/glTF2Sharp.DOM/Schema2/gltf.BufferView.cs

@@ -20,29 +20,32 @@ namespace glTF2Sharp.Schema2
         internal BufferView(Buffer buffer, int? byteLength, int? byteOffset, int? byteStride, BufferMode? target)
         {
             Guard.NotNull(buffer, nameof(buffer));
+            Guard.NotNull(buffer._Data, nameof(buffer));
             Guard.NotNull(buffer.LogicalParent, nameof(buffer));
-            if (byteLength.HasValue) Guard.MustBeGreaterThan(byteLength.Value, 0, nameof(byteLength));
 
-            if (byteOffset.HasValue) Guard.MustBeGreaterThan(byteOffset.Value, 0, nameof(byteOffset));
+            byteLength = byteLength.AsValue(buffer._Data.Length - byteOffset.AsValue(0));
 
-            if (byteStride.HasValue && target.HasValue)
+            Guard.MustBeGreaterThanOrEqualTo(byteLength.AsValue(0), _byteLengthMinimum, nameof(byteLength));
+            Guard.MustBeGreaterThanOrEqualTo(byteOffset.AsValue(0), _byteOffsetMinimum, nameof(byteOffset));
+
+            if (target == BufferMode.ELEMENT_ARRAY_BUFFER)
+            {
+                Guard.IsTrue(byteStride.AsValue(0) == 0, nameof(byteStride));
+            }
+            else if (byteStride.AsValue(0) > 0)
             {
-                if (target.Value == BufferMode.ELEMENT_ARRAY_BUFFER)
-                {
-                    Guard.IsTrue(byteStride.Value == 2 || byteStride.Value == 4, nameof(byteStride));
-                }
-                else if (target.Value == BufferMode.ELEMENT_ARRAY_BUFFER)
-                {
-                    Guard.IsTrue((byteStride.Value % 4) == 0, nameof(byteStride));
-                }
+                // TODO: clarify under which conditions bytestride needs to be defined or forbidden.
+
+                Guard.IsTrue(byteStride.AsValue(0).IsMultipleOf(4), nameof(byteStride));
+                Guard.MustBeBetweenOrEqualTo(byteStride.AsValue(0), _byteStrideMinimum, _byteStrideMaximum, nameof(byteStride));
             }
 
             this._buffer = buffer.LogicalIndex;
 
             this._byteLength = byteLength.AsValue(buffer._Data.Length);
 
-            this._byteOffset = byteOffset;
-            this._byteStride = byteStride;
+            this._byteOffset = byteOffset.AsValue(0).AsNullable(0);
+            this._byteStride = byteStride.AsValue(0).AsNullable(0);
 
             this._target = target;
         }

+ 1 - 1
src/glTF2Sharp.DOM/Schema2/gltf.Serialization.cs

@@ -247,7 +247,7 @@ namespace glTF2Sharp.Schema2
                 for (int i = 0; i < this._buffers.Count; ++i)
                 {
                     var buffer = this._buffers[i];
-                    var bname = $"{name}.{i}.bin";
+                    var bname = this._buffers.Count != 1 ? $"{name}.{i}.bin" : $"{name}.bin";
                     buffer._WriteToExternal(bname, settings.FileWriter);
                 }
             }

+ 42 - 20
src/glTF2Sharp.Tests/Geometry/CreateMeshTests.cs

@@ -13,40 +13,62 @@ namespace glTF2Sharp.Geometry
     public class CreateMeshTests
     {
         [Test]
-        public void CreateMesh1Test()
+        public void CreateTriangleScene()
         {
+            // define the data of a triangle:
+
             var positions = new[]
             {
-                new Vector3(0,1,2),
-                new Vector3(4,1,3),
-                new Vector3(2,3,5),
-                new Vector3(2,4,9),
-                new Vector3(1,3,5),
+                new Vector3(-10,-10,0),
+                new Vector3(0,10,0),
+                new Vector3(10,-10,0)                
             };
 
             var normals = new[]
             {
-                Vector3.UnitX,
-                Vector3.UnitX,
-                Vector3.UnitX,
-                Vector3.UnitY,
                 Vector3.UnitZ,
+                Vector3.UnitZ,
+                Vector3.UnitZ
             };
 
-            var indices = new UInt32[] { 0, 1, 2, 0, 2, 3 };
+            var indices = new UInt32[] { 0, 1, 2 };
+
+            // create a new mesh:
+            var srcMesh = new Mesh();
+
+            // setup a mesh primitive
+            var srcPrimitive = srcMesh.CreatePrimitive();
+            srcPrimitive.AllocateVertices(positions.Length, "POSITION", "NORMAL");          // (#1)
+            srcPrimitive.AllocateIndices(indices.Length, Schema2.PrimitiveType.TRIANGLES);  // (#2)
+
+            // assign vertices and indices
+            srcPrimitive.Vertices[0].SetValues(0, positions);
+            srcPrimitive.Vertices[1].SetValues(0, normals);
+            srcPrimitive.Indices.SetValues(0, indices);            
+
+            // check the values we've set match the input data
+            CollectionAssert.AreEqual(positions, srcPrimitive.Vertices[0].AsVector3Array());
+            CollectionAssert.AreEqual(normals, srcPrimitive.Vertices[1].AsVector3Array());
+            CollectionAssert.AreEqual(indices, srcPrimitive.Indices.AsIntegerArray());
+
+            // Notice that until now, we've been working with objects in the .Geometry namespace.
+
+            // create a new Schema2 scene:
 
-            var primitive = new MeshPrimitive();
-            primitive.SetVertices(5, "POSITION", "NORMAL");
-            primitive.SetIndices(6);
+            var root = Schema2.ModelRoot.CreateNew();                        
+            var scene = root.UseScene("default");
+            var node = scene.AddVisualNode("main scene");
 
-            primitive.Vertices[0].SetValues(0,positions);
-            primitive.Vertices[1].SetValues(0, normals);
-            primitive.Indices.SetValues(0, indices);            
+            node.Mesh = root.CreateMesh();
 
-            CollectionAssert.AreEqual(positions, primitive.Vertices[0].AsVector3Array());
-            CollectionAssert.AreEqual(normals, primitive.Vertices[1].AsVector3Array());
-            CollectionAssert.AreEqual(indices, primitive.Indices.AsIntegerArray());
+            // this assigns the mesh we've created before to this schema mesh.
+            // Notice that the schema buffers being created will be using the
+            // memory allocated by (#1) and (#2)
+            srcMesh.AssignToSchema(node.Mesh);
 
+            root.MergeBuffers();
+            root.AttachToCurrentTest("Triangle.gltf");
+            root.AttachToCurrentTest("Triangle.glb");
         }
     }
 }

+ 1 - 1
src/glTF2Sharp.Tests/Schema2/CreateModelTests.cs

@@ -66,7 +66,7 @@ namespace glTF2Sharp.Schema2
             // save
 
             root.AttachToCurrentTest("result.glb");
-            root.AttachToCurrentTest("result.gltf");
+            root.AttachToCurrentTest("result.gltf");            
         }
     }
 }

+ 15 - 6
src/glTF2Sharp.Tests/TestUtils.cs

@@ -19,26 +19,35 @@ namespace glTF2Sharp
             }
 
             return System.IO.Path.Combine(dir, fxt);
-        }
+        }        
 
-        public static string GetAttachmentPath(this NUnit.Framework.TestContext context, string fileName)
+        public static string GetAttachmentPath(this NUnit.Framework.TestContext context, string fileName, bool ensureDirectoryExists = false)
         {
             if (string.IsNullOrWhiteSpace(fileName)) throw new ArgumentNullException(nameof(fileName));
             if (System.IO.Path.IsPathRooted(fileName)) throw new ArgumentException(nameof(fileName), "path must be a relative path");
 
-            return System.IO.Path.Combine(context.TestDirectory, $"{context.Test.ID}.{fileName}");
+            var path = System.IO.Path.Combine(context.TestDirectory, "TestResults", $"{context.Test.ID}.{fileName}");
+
+            var dir = System.IO.Path.GetDirectoryName(path);
+
+            System.IO.Directory.CreateDirectory(dir);
+
+            return path;
         }
 
         public static void AttachToCurrentTest(this Schema2.ModelRoot model, string fileName)
         {
-            fileName = NUnit.Framework.TestContext.CurrentContext.GetAttachmentPath(fileName);
-
-            if (fileName.ToLower().EndsWith(".gltf")) model.SaveGLTF(fileName, Newtonsoft.Json.Formatting.Indented);
+            fileName = NUnit.Framework.TestContext.CurrentContext.GetAttachmentPath(fileName, true);
+            
             if (fileName.ToLower().EndsWith(".glb"))
             {
                 model.MergeBuffers();
                 model.SaveGLB(fileName);
             }
+            else
+            {
+                model.SaveGLTF(fileName, Newtonsoft.Json.Formatting.Indented);
+            }
 
             NUnit.Framework.TestContext.AddTestAttachment(fileName);
         }

+ 3 - 3
src/glTF2Sharp.Tests/glTF2Sharp.Tests.csproj

@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
     <TargetFramework>netcoreapp2.1</TargetFramework>
@@ -9,10 +9,10 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="LibGit2Sharp" Version="0.25.4" />
+    <PackageReference Include="LibGit2Sharp" Version="0.26.0" />
     <PackageReference Include="nunit" Version="3.11.0" />
     <PackageReference Include="NUnit3TestAdapter" Version="3.12.0" />
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />    
   </ItemGroup>
 
   <ItemGroup>