Sfoglia il codice sorgente

WIP: multi mesh builder

Vicente Penades 6 anni fa
parent
commit
59c47cfbcd

+ 0 - 77
src/SharpGLTF.Toolkit/Geometry/InterleavedMeshBuilder.cs

@@ -1,77 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Numerics;
-using System.Text;
-
-namespace SharpGLTF.Geometry
-{
-    using Collections;
-
-    public 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 properties
-
-        public IReadOnlyList<TVertex> Vertices => _Vertices;
-
-        public IReadOnlyCollection<TMaterial> Materials => _Indices.Keys;
-
-        #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 IEnumerable<(int, int, int)> GetTriangles(TMaterial material)
-        {
-            if (!_Indices.TryGetValue(material, out List<int> indices)) yield break;
-
-            for (int i = 2; i < indices.Count; i += 3)
-            {
-                yield return (indices[i - 2], indices[i - 1], indices[i]);
-            }
-        }
-
-        public IReadOnlyList<int> GetIndices(TMaterial material)
-        {
-            return _Indices.TryGetValue(material, out List<int> indices) ? indices : null;
-        }
-
-        #endregion
-    }
-}

+ 143 - 0
src/SharpGLTF.Toolkit/Geometry/SkinnedMeshBuilder.cs

@@ -0,0 +1,143 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Linq;
+
+namespace SharpGLTF.Geometry
+{
+    using Collections;
+
+    public class SkinnedPrimitiveBuilder<TVertex, TSkin, TMaterial>
+        where TVertex : struct
+        where TSkin : struct
+    {
+        #region lifecycle
+
+        internal SkinnedPrimitiveBuilder(SkinnedMeshBuilder<TVertex, TSkin, TMaterial> mesh, TMaterial material)
+        {
+            this._Mesh = mesh;
+            this._Material = material;
+        }
+
+        #endregion
+
+        #region data
+
+        private readonly SkinnedMeshBuilder<TVertex, TSkin, TMaterial> _Mesh;
+
+        private readonly TMaterial _Material;
+
+        private readonly VertexColumn<(TVertex, TSkin)> _Vertices = new VertexColumn<(TVertex, TSkin)>();
+        private readonly List<int> _Indices = new List<int>();
+
+        #endregion
+
+        #region properties
+
+        public SkinnedMeshBuilder<TVertex, TSkin, TMaterial> Mesh => _Mesh;
+
+        public TMaterial Material => _Material;
+
+        public IReadOnlyList<(TVertex, TSkin)> Vertices => _Vertices;
+
+        public IReadOnlyList<int> Indices => _Indices;
+
+        public IEnumerable<(int, int, int)> Triangles
+        {
+            get
+            {
+                for (int i = 2; i < _Indices.Count; i += 3)
+                {
+                    yield return (_Indices[i - 2], _Indices[i - 1], _Indices[i]);
+                }
+            }
+        }
+
+        #endregion
+
+        #region API
+
+        public void AddTriangle((TVertex, TSkin) a, (TVertex, TSkin) b, (TVertex, TSkin) 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;
+
+            _Indices.Add(aa);
+            _Indices.Add(bb);
+            _Indices.Add(cc);
+        }
+
+        #endregion
+    }
+
+    public class SkinnedMeshBuilder<TVertex, TSkin, TMaterial>
+        where TVertex : struct
+        where TSkin : struct
+    {
+        #region lifecycle
+
+        public SkinnedMeshBuilder(string name = null)
+        {
+            this.Name = name;
+        }
+
+        #endregion
+
+        #region data
+
+        private readonly Dictionary<TMaterial, SkinnedPrimitiveBuilder<TVertex,TSkin, TMaterial>> _Primitives = new Dictionary<TMaterial, SkinnedPrimitiveBuilder<TVertex, TSkin, TMaterial>>();
+
+        #endregion
+
+        #region properties
+
+        public string Name { get; set; }
+
+        public IReadOnlyCollection<SkinnedPrimitiveBuilder<TVertex, TSkin, TMaterial>> Primitives => _Primitives.Values;
+
+        #endregion
+
+        #region API
+
+        public void AddPolygon(TMaterial material, params (TVertex, TSkin)[] points)
+        {
+            for (int i = 2; i < points.Length; ++i)
+            {
+                AddTriangle(material, points[0], points[i - 1], points[i]);
+            }
+        }
+
+        public void AddTriangle(TMaterial material, (TVertex, TSkin) a, (TVertex, TSkin) b, (TVertex, TSkin) c)
+        {
+            if (!_Primitives.TryGetValue(material, out SkinnedPrimitiveBuilder<TVertex, TSkin, TMaterial> primitive))
+            {
+                primitive = new SkinnedPrimitiveBuilder<TVertex, TSkin, TMaterial>(this, material);
+                _Primitives[material] = primitive;
+            }
+
+            primitive.AddTriangle(a, b, c);
+        }
+
+        public IEnumerable<(int, int, int)> GetTriangles(TMaterial material)
+        {
+            if (_Primitives.TryGetValue(material, out SkinnedPrimitiveBuilder<TVertex, TSkin, TMaterial> primitive)) return primitive.Triangles;
+
+            return Enumerable.Empty<(int, int, int)>();
+        }
+
+        public IReadOnlyList<int> GetIndices(TMaterial material)
+        {
+            if (_Primitives.TryGetValue(material, out SkinnedPrimitiveBuilder<TVertex, TSkin, TMaterial> primitive)) return primitive.Indices;
+
+            return new int[0];
+        }
+
+        #endregion
+    }
+}

+ 142 - 0
src/SharpGLTF.Toolkit/Geometry/StaticMeshBuilder.cs

@@ -0,0 +1,142 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+using System.Text;
+
+namespace SharpGLTF.Geometry
+{
+    using Collections;
+
+    public class StaticPrimitiveBuilder<TVertex, TMaterial>
+        where TVertex : struct
+    {
+        #region lifecycle
+
+        internal StaticPrimitiveBuilder(StaticMeshBuilder<TVertex, TMaterial> mesh, TMaterial material)
+        {
+            this._Mesh = mesh;
+            this._Material = material;
+        }
+
+        #endregion
+
+        #region data
+
+        private readonly StaticMeshBuilder<TVertex, TMaterial> _Mesh;
+
+        private readonly TMaterial _Material;
+
+        private readonly VertexColumn<TVertex> _Vertices = new VertexColumn<TVertex>();
+        private readonly List<int> _Indices = new List<int>();
+
+        #endregion
+
+        #region properties
+
+        public StaticMeshBuilder<TVertex, TMaterial> Mesh => _Mesh;
+
+        public TMaterial Material => _Material;
+
+        public IReadOnlyList<TVertex> Vertices => _Vertices;
+
+        public IReadOnlyList<int> Indices => _Indices;
+
+        public IEnumerable<(int, int, int)> Triangles
+        {
+            get
+            {
+                for (int i = 2; i < _Indices.Count; i += 3)
+                {
+                    yield return (_Indices[i - 2], _Indices[i - 1], _Indices[i]);
+                }
+            }
+        }
+
+        #endregion
+
+        #region API
+
+        public void AddTriangle(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;
+
+            _Indices.Add(aa);
+            _Indices.Add(bb);
+            _Indices.Add(cc);
+        }
+
+        #endregion
+    }
+
+    public class StaticMeshBuilder<TVertex, TMaterial>
+        where TVertex : struct
+    {
+        #region lifecycle
+
+        public StaticMeshBuilder(string name = null)
+        {
+            this.Name = name;
+        }
+
+        #endregion
+
+        #region data
+
+        private readonly Dictionary<TMaterial, StaticPrimitiveBuilder<TVertex, TMaterial>> _Primitives = new Dictionary<TMaterial, StaticPrimitiveBuilder<TVertex, TMaterial>>();
+
+        #endregion
+
+        #region properties
+
+        public string Name { get; set; }
+
+        public IReadOnlyCollection<StaticPrimitiveBuilder<TVertex, TMaterial>> Primitives => _Primitives.Values;
+
+        #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)
+        {
+            if (!_Primitives.TryGetValue(material, out StaticPrimitiveBuilder<TVertex, TMaterial> primitive))
+            {
+                primitive = new StaticPrimitiveBuilder<TVertex, TMaterial>(this, material);
+                _Primitives[material] = primitive;
+            }
+
+            primitive.AddTriangle(a, b, c);
+        }
+
+        public IEnumerable<(int, int, int)> GetTriangles(TMaterial material)
+        {
+            if (_Primitives.TryGetValue(material, out StaticPrimitiveBuilder<TVertex, TMaterial> primitive)) return primitive.Triangles;
+
+            return Enumerable.Empty<(int, int, int)>();
+        }
+
+        public IReadOnlyList<int> GetIndices(TMaterial material)
+        {
+            if (_Primitives.TryGetValue(material, out StaticPrimitiveBuilder<TVertex, TMaterial> primitive)) return primitive.Indices;
+
+            return new int[0];
+        }
+
+        #endregion
+    }
+}

+ 3 - 8
src/SharpGLTF.Toolkit/Geometry/VertexTypes/SkinnedVertices.cs

@@ -5,25 +5,20 @@ using System.Text;
 
 
 namespace SharpGLTF.Geometry.VertexTypes
 namespace SharpGLTF.Geometry.VertexTypes
 {
 {
-    public struct SkinnedPosition
+    public struct SkinJoints4
     {
     {
-        public SkinnedPosition(float px, float py, float pz, int jointIndex)
+        public SkinJoints4(int jointIndex)
         {
         {
-            Position = new Vector3(px, py, pz);
             Joints_0 = new Vector4(jointIndex);
             Joints_0 = new Vector4(jointIndex);
             Weights_0 = Vector4.UnitX;
             Weights_0 = Vector4.UnitX;
         }
         }
 
 
-        public SkinnedPosition(float px, float py, float pz, int jointIndex1, int jointIndex2)
+        public SkinJoints4(int jointIndex1, int jointIndex2)
         {
         {
-            Position = new Vector3(px, py, pz);
             Joints_0 = new Vector4(jointIndex1, jointIndex2, 0, 0);
             Joints_0 = new Vector4(jointIndex1, jointIndex2, 0, 0);
             Weights_0 = new Vector4(0.5f, 0.5f, 0, 0);
             Weights_0 = new Vector4(0.5f, 0.5f, 0, 0);
         }
         }
 
 
-        [VertexAttribute("POSITION")]
-        public Vector3 Position;
-
         [VertexAttribute("JOINTS_0", Schema2.EncodingType.UNSIGNED_BYTE, false)]
         [VertexAttribute("JOINTS_0", Schema2.EncodingType.UNSIGNED_BYTE, false)]
         public Vector4 Joints_0;
         public Vector4 Joints_0;
 
 

+ 51 - 2
src/SharpGLTF.Toolkit/Geometry/VertexTypes/StaticVertices.cs

@@ -5,9 +5,20 @@ using System.Text;
 
 
 namespace SharpGLTF.Geometry.VertexTypes
 namespace SharpGLTF.Geometry.VertexTypes
 {
 {
-    public struct StaticPositionNormal
+    public struct VertexPosition
     {
     {
-        public StaticPositionNormal(float px, float py, float pz, float nx, float ny, float nz)
+        public VertexPosition(float px, float py, float pz)
+        {
+            Position = new Vector3(px, py, pz);
+        }
+
+        [VertexAttribute("POSITION")]
+        public Vector3 Position;
+    }
+
+    public struct VertexPositionNormal
+    {
+        public VertexPositionNormal(float px, float py, float pz, float nx, float ny, float nz)
         {
         {
             Position = new Vector3(px, py, pz);
             Position = new Vector3(px, py, pz);
             Normal = Vector3.Normalize(new Vector3(nx, ny, nz));
             Normal = Vector3.Normalize(new Vector3(nx, ny, nz));
@@ -19,4 +30,42 @@ namespace SharpGLTF.Geometry.VertexTypes
         [VertexAttribute("NORMAL")]
         [VertexAttribute("NORMAL")]
         public Vector3 Normal;
         public Vector3 Normal;
     }
     }
+
+    public struct VertexPositionNormalColor1
+    {
+        public VertexPositionNormalColor1(Vector3 pos, Vector3 nrm, Vector4 color)
+        {
+            Position = pos;
+            Normal = Vector3.Normalize(nrm);
+            Color = color;
+        }
+
+        [VertexAttribute("POSITION")]
+        public Vector3 Position;
+
+        [VertexAttribute("NORMAL")]
+        public Vector3 Normal;
+
+        [VertexAttribute("COLOR_0")]
+        public Vector4 Color;
+    }
+
+    public struct VertexPositionNormalTex1
+    {
+        public VertexPositionNormalTex1(Vector3 pos, Vector3 nrm, Vector2 tex)
+        {
+            Position = pos;
+            Normal = Vector3.Normalize(nrm);
+            TexCoord = tex;
+        }
+
+        [VertexAttribute("POSITION")]
+        public Vector3 Position;
+
+        [VertexAttribute("NORMAL")]
+        public Vector3 Normal;
+
+        [VertexAttribute("TEXCOORD_0")]
+        public Vector2 TexCoord;
+    }
 }
 }

+ 137 - 8
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexUtils.cs

@@ -8,9 +8,9 @@ namespace SharpGLTF.Geometry.VertexTypes
 {
 {
     public static class VertexUtils
     public static class VertexUtils
     {
     {
-        public static System.Reflection.FieldInfo GetVertexField(Type type, string attributeName)
+        public static System.Reflection.FieldInfo GetVertexField(Type vertexType, string attributeName)
         {
         {
-            foreach (var finfo in type.GetFields())
+            foreach (var finfo in vertexType.GetFields())
             {
             {
                 var attribute = _GetAccessor(finfo);
                 var attribute = _GetAccessor(finfo);
 
 
@@ -23,11 +23,11 @@ namespace SharpGLTF.Geometry.VertexTypes
             return null;
             return null;
         }
         }
 
 
-        public static MemoryAccessInfo[] GetVertexAttributes(Type type, int itemsCount)
+        public static MemoryAccessInfo[] GetVertexAttributes(Type vertexType, int itemsCount)
         {
         {
             var attributes = new List<MemoryAccessInfo>();
             var attributes = new List<MemoryAccessInfo>();
 
 
-            foreach (var finfo in type.GetFields())
+            foreach (var finfo in vertexType.GetFields())
             {
             {
                 var attribute = _GetAccessor(finfo);
                 var attribute = _GetAccessor(finfo);
 
 
@@ -44,6 +44,79 @@ namespace SharpGLTF.Geometry.VertexTypes
             return array;
             return array;
         }
         }
 
 
+        public static MemoryAccessInfo[] GetVertexAttributes(Type vertexType, Type skinType, int itemsCount)
+        {
+            var attributes = new List<MemoryAccessInfo>();
+
+            foreach (var finfo in vertexType.GetFields())
+            {
+                var attribute = _GetAccessor(finfo);
+                if (attribute.HasValue) attributes.Add(attribute.Value);
+            }
+
+            foreach (var finfo in skinType.GetFields())
+            {
+                var attribute = _GetAccessor(finfo);
+                if (attribute.HasValue) attributes.Add(attribute.Value);
+            }
+
+            var array = attributes.ToArray();
+
+            MemoryAccessInfo.SetInterleavedInfo(array, 0, itemsCount);
+
+            return array;
+        }
+
+        public static IEnumerable<MemoryAccessor[]> CreateVertexMemoryAccessors<TVertex>(this IEnumerable<IReadOnlyList<TVertex>> vertexBlocks)
+            where TVertex : struct
+        {
+            // get attributes
+            var totalCount = vertexBlocks.Sum(item => item.Count);
+            var attributes = GetVertexAttributes(typeof(TVertex), totalCount);
+
+            // create master vertex buffer
+            int byteStride = attributes[0].ByteStride;
+            var vbytes = new Byte[byteStride * totalCount];
+            var vbuffer = new ArraySegment<byte>(vbytes);
+
+            var baseVertexIndex = 0;
+
+            foreach (var block in vertexBlocks)
+            {
+                yield return MemoryAccessInfo
+                    .Slice(attributes, baseVertexIndex, block.Count)
+                    .Select(item => new MemoryAccessor(vbuffer, item))
+                    .ToArray();
+
+                baseVertexIndex += block.Count;
+            }
+        }
+
+        public static IEnumerable<MemoryAccessor[]> CreateIndexMemoryAccessors(this IEnumerable<IReadOnlyList<Int32>> indexBlocks)
+        {
+            // get attributes
+            var totalCount = indexBlocks.Sum(item => item.Count);
+
+            // create master index buffer
+            var vbytes = new Byte[4 * totalCount];
+            var vbuffer = new ArraySegment<byte>(vbytes);
+
+            var baseIndicesIndex = 0;
+
+            throw new NotImplementedException();
+
+            /*
+            foreach (var block in indexBlocks)
+            {
+                yield return MemoryAccessInfo
+                    .Slice(attributes, baseVertexIndex, block.Count)
+                    .Select(item => new MemoryAccessor(vbuffer, item))
+                    .ToArray();
+
+                baseIndicesIndex += block.Count;
+            }*/
+        }
+
         private static MemoryAccessInfo? _GetAccessor(System.Reflection.FieldInfo finfo)
         private static MemoryAccessInfo? _GetAccessor(System.Reflection.FieldInfo finfo)
         {
         {
             var attribute = finfo.GetCustomAttributes(true)
             var attribute = finfo.GetCustomAttributes(true)
@@ -66,7 +139,7 @@ namespace SharpGLTF.Geometry.VertexTypes
             return new MemoryAccessInfo(attribute.Name, 0, 0, 0, dimensions.Value, attribute.Encoding, attribute.Normalized);
             return new MemoryAccessInfo(attribute.Name, 0, 0, 0, dimensions.Value, attribute.Encoding, attribute.Normalized);
         }
         }
 
 
-        public static Single[] GetScalarColumn<TVertex>(this System.Reflection.FieldInfo finfo, IReadOnlyList<TVertex> vertices)
+        internal static Single[] GetScalarColumn<TVertex>(this System.Reflection.FieldInfo finfo, IReadOnlyList<TVertex> vertices)
         {
         {
             var dst = new Single[vertices.Count];
             var dst = new Single[vertices.Count];
 
 
@@ -78,7 +151,7 @@ namespace SharpGLTF.Geometry.VertexTypes
             return dst;
             return dst;
         }
         }
 
 
-        public static Vector2[] GetVector2Column<TVertex>(this System.Reflection.FieldInfo finfo, IReadOnlyList<TVertex> vertices)
+        internal static Vector2[] GetVector2Column<TVertex>(this System.Reflection.FieldInfo finfo, IReadOnlyList<TVertex> vertices)
         {
         {
             var dst = new Vector2[vertices.Count];
             var dst = new Vector2[vertices.Count];
 
 
@@ -90,7 +163,7 @@ namespace SharpGLTF.Geometry.VertexTypes
             return dst;
             return dst;
         }
         }
 
 
-        public static Vector3[] GetVector3Column<TVertex>(this System.Reflection.FieldInfo finfo, IReadOnlyList<TVertex> vertices)
+        internal static Vector3[] GetVector3Column<TVertex>(this System.Reflection.FieldInfo finfo, IReadOnlyList<TVertex> vertices)
         {
         {
             var dst = new Vector3[vertices.Count];
             var dst = new Vector3[vertices.Count];
 
 
@@ -102,7 +175,7 @@ namespace SharpGLTF.Geometry.VertexTypes
             return dst;
             return dst;
         }
         }
 
 
-        public static Vector4[] GetVector4Column<TVertex>(this System.Reflection.FieldInfo finfo, IReadOnlyList<TVertex> vertices)
+        internal static Vector4[] GetVector4Column<TVertex>(this System.Reflection.FieldInfo finfo, IReadOnlyList<TVertex> vertices)
         {
         {
             var dst = new Vector4[vertices.Count];
             var dst = new Vector4[vertices.Count];
 
 
@@ -113,5 +186,61 @@ namespace SharpGLTF.Geometry.VertexTypes
 
 
             return dst;
             return dst;
         }
         }
+
+        internal static Single[] GetScalarColumn<TVertex, TSkin>(this System.Reflection.FieldInfo finfo, IReadOnlyList<(TVertex, TSkin)> vertices, bool vertexOrSkin)
+        {
+            var dst = new Single[vertices.Count];
+
+            for (int i = 0; i < dst.Length; ++i)
+            {
+                var v = vertices[i];
+
+                dst[i] = vertexOrSkin ? (Single)finfo.GetValue(v.Item2) : (Single)finfo.GetValue(v.Item1);
+            }
+
+            return dst;
+        }
+
+        internal static Vector2[] GetVector2Column<TVertex, TSkin>(this System.Reflection.FieldInfo finfo, IReadOnlyList<(TVertex, TSkin)> vertices, bool vertexOrSkin)
+        {
+            var dst = new Vector2[vertices.Count];
+
+            for (int i = 0; i < dst.Length; ++i)
+            {
+                var v = vertices[i];
+
+                dst[i] = vertexOrSkin ? (Vector2)finfo.GetValue(v.Item2) : (Vector2)finfo.GetValue(v.Item1);
+            }
+
+            return dst;
+        }
+
+        internal static Vector3[] GetVector3Column<TVertex, TSkin>(this System.Reflection.FieldInfo finfo, IReadOnlyList<(TVertex, TSkin)> vertices, bool vertexOrSkin)
+        {
+            var dst = new Vector3[vertices.Count];
+
+            for (int i = 0; i < dst.Length; ++i)
+            {
+                var v = vertices[i];
+
+                dst[i] = vertexOrSkin ? (Vector3)finfo.GetValue(v.Item2) : (Vector3)finfo.GetValue(v.Item1);
+            }
+
+            return dst;
+        }
+
+        internal static Vector4[] GetVector4Column<TVertex, TSkin>(this System.Reflection.FieldInfo finfo, IReadOnlyList<(TVertex, TSkin)> vertices, bool vertexOrSkin)
+        {
+            var dst = new Vector4[vertices.Count];
+
+            for (int i = 0; i < dst.Length; ++i)
+            {
+                var v = vertices[i];
+
+                dst[i] = vertexOrSkin ? (Vector4)finfo.GetValue(v.Item2) : (Vector4)finfo.GetValue(v.Item1);
+            }
+
+            return dst;
+        }
     }
     }
 }
 }

+ 58 - 8
src/SharpGLTF.Toolkit/Schema2/AccessorExtensions.cs

@@ -9,7 +9,8 @@ namespace SharpGLTF.Schema2
 
 
     public static partial class Toolkit
     public static partial class Toolkit
     {
     {
-        public static IReadOnlyDictionary<string, Accessor> CreateInterleavedVertexAccessors<TVertex>(this ModelRoot root, IReadOnlyList<TVertex> vertices)
+        public static IReadOnlyDictionary<string, Accessor> CreateStaticVertexAccessors<TVertex>(this ModelRoot root, IReadOnlyList<TVertex> vertices)
+            where TVertex : struct
         {
         {
             // get vertex attributes from TVertex type using reflection
             // get vertex attributes from TVertex type using reflection
             var attributes = VertexUtils.GetVertexAttributes(typeof(TVertex), vertices.Count);
             var attributes = VertexUtils.GetVertexAttributes(typeof(TVertex), vertices.Count);
@@ -17,26 +18,75 @@ namespace SharpGLTF.Schema2
             // create vertex buffer
             // create vertex buffer
             int byteStride = attributes[0].ByteStride;
             int byteStride = attributes[0].ByteStride;
             var vbytes = new Byte[byteStride * vertices.Count];
             var vbytes = new Byte[byteStride * vertices.Count];
-
             var vbuffer = root.UseBufferView(new ArraySegment<byte>(vbytes), byteStride, BufferMode.ARRAY_BUFFER);
             var vbuffer = root.UseBufferView(new ArraySegment<byte>(vbytes), byteStride, BufferMode.ARRAY_BUFFER);
 
 
+            return _CreateAccessors(root, vbuffer, attributes, 0, vertices);
+        }
+
+        internal static IReadOnlyDictionary<string, Accessor> _CreateAccessors<TVertex>(ModelRoot root, BufferView vbuffer, Geometry.MemoryAccessInfo[] attributes, int vertexStart, IReadOnlyList<TVertex> vertices)
+        {
+            attributes = Geometry.MemoryAccessInfo.Slice(attributes, vertexStart, vertices.Count);
+
             // create vertex accessors
             // create vertex accessors
             var vertexAccessors = new Dictionary<String, Accessor>();
             var vertexAccessors = new Dictionary<String, Accessor>();
 
 
             foreach (var attribute in attributes)
             foreach (var attribute in attributes)
             {
             {
-                var accessor = root.CreateAccessor(attribute.Name);
-
                 var field = VertexUtils.GetVertexField(typeof(TVertex), attribute.Name);
                 var field = VertexUtils.GetVertexField(typeof(TVertex), attribute.Name);
 
 
-                if (field.FieldType == typeof(Vector2)) accessor.SetVertexData(vbuffer, attribute.ByteOffset, field.GetVector2Column(vertices), attribute.Encoding, attribute.Normalized);
-                if (field.FieldType == typeof(Vector3)) accessor.SetVertexData(vbuffer, attribute.ByteOffset, field.GetVector3Column(vertices), attribute.Encoding, attribute.Normalized);
-                if (field.FieldType == typeof(Vector4)) accessor.SetVertexData(vbuffer, attribute.ByteOffset, field.GetVector4Column(vertices), attribute.Encoding, attribute.Normalized);
+                vertexAccessors[attribute.Name] = _CreateAccessor(root, vbuffer, attribute, vertices, field);
+            }
 
 
-                vertexAccessors[attribute.Name] = accessor;
+            return vertexAccessors;
+        }
+
+        public static IReadOnlyDictionary<string, Accessor> CreateSkinedVertexAccessors<TVertex, TSkin>(this ModelRoot root, IReadOnlyList<(TVertex, TSkin)> vertices)
+        {
+            // get vertex attributes from TVertex and TSkin types using reflection
+            var attributes = VertexUtils.GetVertexAttributes(typeof(TVertex), typeof(TSkin), vertices.Count);
+
+            // create vertex buffer
+            int byteStride = attributes[0].ByteStride;
+            var vbytes = new Byte[byteStride * vertices.Count];
+            var vbuffer = root.UseBufferView(new ArraySegment<byte>(vbytes), byteStride, BufferMode.ARRAY_BUFFER);
+
+            // create vertex accessors
+            var vertexAccessors = new Dictionary<String, Accessor>();
+
+            foreach (var attribute in attributes)
+            {
+                var vfield = VertexUtils.GetVertexField(typeof(TVertex), attribute.Name);
+                var sfield = VertexUtils.GetVertexField(typeof(TSkin), attribute.Name);
+
+                if (vfield != null)
+                {
+                    vertexAccessors[attribute.Name] = root._CreateAccessor(vbuffer, attribute, vertices, vfield, false);
+                }
+                else if (sfield != null)
+                {
+                    vertexAccessors[attribute.Name] = root._CreateAccessor(vbuffer, attribute, vertices, sfield, true);
+                }
             }
             }
 
 
             return vertexAccessors;
             return vertexAccessors;
         }
         }
+
+        private static Accessor _CreateAccessor<TVertex>(this ModelRoot root, BufferView vbuffer, Geometry.MemoryAccessInfo attribute, IReadOnlyList<TVertex> vertices, System.Reflection.FieldInfo field)
+        {
+            var accessor = root.CreateAccessor(attribute.Name);
+            if (field.FieldType == typeof(Vector2)) accessor.SetVertexData(vbuffer, attribute.ByteOffset, field.GetVector2Column(vertices), attribute.Encoding, attribute.Normalized);
+            if (field.FieldType == typeof(Vector3)) accessor.SetVertexData(vbuffer, attribute.ByteOffset, field.GetVector3Column(vertices), attribute.Encoding, attribute.Normalized);
+            if (field.FieldType == typeof(Vector4)) accessor.SetVertexData(vbuffer, attribute.ByteOffset, field.GetVector4Column(vertices), attribute.Encoding, attribute.Normalized);
+            return accessor;
+        }
+
+        private static Accessor _CreateAccessor<TVertex, TSkin>(this ModelRoot root, BufferView vbuffer, Geometry.MemoryAccessInfo attribute, IReadOnlyList<(TVertex, TSkin)> vertices, System.Reflection.FieldInfo field, bool vertexOrSkin)
+        {
+            var accessor = root.CreateAccessor(attribute.Name);
+            if (field.FieldType == typeof(Vector2)) accessor.SetVertexData(vbuffer, attribute.ByteOffset, field.GetVector2Column(vertices, vertexOrSkin), attribute.Encoding, attribute.Normalized);
+            if (field.FieldType == typeof(Vector3)) accessor.SetVertexData(vbuffer, attribute.ByteOffset, field.GetVector3Column(vertices, vertexOrSkin), attribute.Encoding, attribute.Normalized);
+            if (field.FieldType == typeof(Vector4)) accessor.SetVertexData(vbuffer, attribute.ByteOffset, field.GetVector4Column(vertices, vertexOrSkin), attribute.Encoding, attribute.Normalized);
+            return accessor;
+        }
     }
     }
 }
 }

+ 129 - 8
src/SharpGLTF.Toolkit/Schema2/MeshExtensions.cs

@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Numerics;
 using System.Numerics;
 using System.Text;
 using System.Text;
+using System.Linq;
 
 
 namespace SharpGLTF.Schema2
 namespace SharpGLTF.Schema2
 {
 {
@@ -9,19 +10,86 @@ namespace SharpGLTF.Schema2
 
 
     public static partial class Toolkit
     public static partial class Toolkit
     {
     {
-        public static Mesh CreateMesh<TVertex>(this ModelRoot root, string name, Geometry.InterleavedMeshBuilder<TVertex, Material> meshBuilder)
+        public static Mesh CreateMesh<TVertex>(this ModelRoot root, Geometry.StaticMeshBuilder<TVertex, Material> meshBuilder)
             where TVertex : struct
             where TVertex : struct
         {
         {
-            return root.CreateMesh<TVertex, Material>(name, meshBuilder, k => k);
+            return root.CreateMesh<TVertex, Material>(k => k, meshBuilder);
         }
         }
 
 
-        public static Mesh CreateMesh<TVertex, TMaterial>(this ModelRoot root, string name, Geometry.InterleavedMeshBuilder<TVertex, TMaterial> meshBuilder, Func<TMaterial,Material> materialEvaluator)
+        public static Mesh CreateMesh<TVertex, TMaterial>(this ModelRoot root, Func<TMaterial, Material> materialEvaluator, Geometry.StaticMeshBuilder<TVertex, TMaterial> meshBuilder)
             where TVertex : struct
             where TVertex : struct
         {
         {
-            var dstMesh = root.CreateMesh(name);
+            return root.CreateMeshes(materialEvaluator, meshBuilder)[0];
+        }
+
+        public static Mesh[] CreateMeshes<TVertex, TMaterial>(this ModelRoot root, Func<TMaterial, Material> materialEvaluator, params Geometry.StaticMeshBuilder<TVertex, TMaterial>[] meshBuilders)
+            where TVertex : struct
+        {
+            var vertexBlocks = Geometry.VertexTypes.VertexUtils.CreateVertexMemoryAccessors
+                (
+                meshBuilders
+                .SelectMany(item => item.Primitives)
+                .Select(item => item.Vertices)
+                ).ToList();
+
+            var dstMeshes = meshBuilders
+                .Select(item => root.CreateMesh(item.Name))
+                .ToArray();
+
+            var pidx = 0;
+
+            for (int i = 0; i < dstMeshes.Length; ++i)
+            {
+                var srcMesh = meshBuilders[i];
+                var dstMesh = dstMeshes[i];
+
+                foreach (var p in srcMesh.Primitives)
+                {
+                    var vblock = vertexBlocks[pidx];
+
+                    var prim = dstMesh.CreatePrimitive();
+
+                    foreach (var a in vblock)
+                    {
+                        var accessor = root.CreateAccessor(a.Attribute.Name);
+                        accessor.SetVertexData(a);
+                        prim.SetVertexAccessor(a.Attribute.Name, accessor);
+                    }
+
+                    ++pidx;
+                }
+            }
+
+            return dstMeshes;
+        }
+
+        public static Mesh CreateMesh<TVertex, TSkin, TMaterial>(this ModelRoot root, Func<TMaterial, Material> materialEvaluator, Geometry.SkinnedMeshBuilder<TVertex, TSkin, TMaterial> meshBuilder)
+            where TVertex : struct
+            where TSkin : struct
+        {
+            return root.CreateMeshes(materialEvaluator, meshBuilder)[0];
+        }
+
+        public static Mesh[] CreateMeshes<TVertex, TSkin, TMaterial>(this ModelRoot root, Func<TMaterial, Material> materialEvaluator, params Geometry.SkinnedMeshBuilder<TVertex, TSkin, TMaterial>[] meshBuilders)
+            where TVertex : struct
+            where TSkin : struct
+        {
+            var dstMeshes = meshBuilders
+                .Select(item => root.CreateMesh(item.Name))
+                .ToArray();
+
+            return dstMeshes;
+        }
+
+        /*
+
+        public static Mesh CreateMesh<TVertex, TMaterial>(this ModelRoot root, Geometry.StaticMeshBuilder<TVertex, TMaterial> meshBuilder, Func<TMaterial, Material> materialEvaluator)
+            where TVertex : struct
+        {
+            var dstMesh = root.CreateMesh(meshBuilder.Name);
 
 
             // create vertex accessors
             // create vertex accessors
-            var vertexAccessors = root.CreateInterleavedVertexAccessors(meshBuilder.Vertices);
+            var vertexAccessors = root.CreateStaticVertexAccessors(meshBuilder.Vertices);
 
 
             foreach (var mkey in meshBuilder.Materials)
             foreach (var mkey in meshBuilder.Materials)
             {
             {
@@ -48,9 +116,57 @@ namespace SharpGLTF.Schema2
             return dstMesh;
             return dstMesh;
         }
         }
 
 
+        public static Mesh CreateMesh<TVertex, TSkin, TMaterial>(this ModelRoot root, Geometry.SkinnedMeshBuilder<TVertex, TSkin, TMaterial> meshBuilder, Func<TMaterial, Material> materialEvaluator)
+            where TVertex : struct
+            where TSkin : struct
+        {
+            var dstMesh = root.CreateMesh(meshBuilder.Name);
+
+            // create vertex accessors
+            var vertexAccessors = root.CreateSkinedVertexAccessors(meshBuilder.Vertices);
+
+            foreach (var mkey in meshBuilder.Materials)
+            {
+                var indices = meshBuilder.GetIndices(mkey);
+
+                // create index buffer
+                var ibytes = new Byte[4 * indices.Count];
+                var ibuffer = root.UseBufferView(new ArraySegment<byte>(ibytes), 0, BufferMode.ELEMENT_ARRAY_BUFFER);
+
+                var indicesAccessor = root
+                    .CreateAccessor("Indices");
+
+                indicesAccessor.SetIndexData(ibuffer, 0, indices);
+
+                // create mesh primitive
+                var prim = dstMesh.CreatePrimitive();
+                foreach (var va in vertexAccessors) prim.SetVertexAccessor(va.Key, va.Value);
+                prim.SetIndexAccessor(indicesAccessor);
+                prim.DrawPrimitiveType = PrimitiveType.TRIANGLES;
+
+                prim.Material = materialEvaluator(mkey);
+            }
+
+            return dstMesh;
+        }
+        */
+
+        #region accessors
+
+        public static MeshPrimitive WithVertexAccessors<TVertex>(this MeshPrimitive primitive, IReadOnlyList<Geometry.MemoryAccessor> memAccessors)
+        where TVertex : struct
+        {
+            var accessors = primitive.LogicalParent.LogicalParent.CreateStaticVertexAccessors(memAccessors);
+
+            foreach (var va in accessors) primitive.SetVertexAccessor(va.Key, va.Value);
+
+            return primitive;
+        }
+
         public static MeshPrimitive WithVertexAccessors<TVertex>(this MeshPrimitive primitive, IReadOnlyList<TVertex> vertices)
         public static MeshPrimitive WithVertexAccessors<TVertex>(this MeshPrimitive primitive, IReadOnlyList<TVertex> vertices)
+            where TVertex : struct
         {
         {
-            var accessors = primitive.LogicalParent.LogicalParent.CreateInterleavedVertexAccessors(vertices);
+            var accessors = primitive.LogicalParent.LogicalParent.CreateStaticVertexAccessors(vertices);
 
 
             foreach (var va in accessors) primitive.SetVertexAccessor(va.Key, va.Value);
             foreach (var va in accessors) primitive.SetVertexAccessor(va.Key, va.Value);
 
 
@@ -67,11 +183,10 @@ namespace SharpGLTF.Schema2
             array.FillFrom(0, values);
             array.FillFrom(0, values);
 
 
             var accessor = root.CreateAccessor();
             var accessor = root.CreateAccessor();
+            primitive.SetVertexAccessor(attribute, accessor);
 
 
             accessor.SetVertexData(view, 0, values.Count, DimensionType.VEC2, EncodingType.FLOAT, false);
             accessor.SetVertexData(view, 0, values.Count, DimensionType.VEC2, EncodingType.FLOAT, false);
 
 
-            primitive.SetVertexAccessor(attribute, accessor);
-
             return primitive;
             return primitive;
         }
         }
 
 
@@ -140,10 +255,16 @@ namespace SharpGLTF.Schema2
             return primitive;
             return primitive;
         }
         }
 
 
+        #endregion
+
+        #region material
+
         public static MeshPrimitive WithMaterial(this MeshPrimitive primitive, Material material)
         public static MeshPrimitive WithMaterial(this MeshPrimitive primitive, Material material)
         {
         {
             primitive.Material = material;
             primitive.Material = material;
             return primitive;
             return primitive;
         }
         }
+
+        #endregion
     }
     }
 }
 }

+ 16 - 1
src/SharpGLTF/Geometry/MemoryAccessor.cs

@@ -140,6 +140,21 @@ namespace SharpGLTF.Geometry
             return byteStride;
             return byteStride;
         }
         }
 
 
+        public static MemoryAccessInfo[] Slice(MemoryAccessInfo[] attributes, int start, int count)
+        {
+            var dst = new MemoryAccessInfo[attributes.Length];
+
+            for (int i = 0; i < dst.Length; ++i)
+            {
+                var a = attributes[i];
+                a.ByteOffset += a.ByteStride * start;
+                a.ItemsCount = Math.Min(a.ItemsCount, count);
+                dst[i] = a;
+            }
+
+            return dst;
+        }
+
         #endregion
         #endregion
     }
     }
 
 
@@ -150,7 +165,7 @@ namespace SharpGLTF.Geometry
     {
     {
         #region constructor
         #region constructor
 
 
-        public MemoryAccessor(MemoryAccessInfo info, ArraySegment<Byte> data)
+        public MemoryAccessor(ArraySegment<Byte> data, MemoryAccessInfo info)
         {
         {
             this.Attribute = info;
             this.Attribute = info;
             this.Data = data;
             this.Data = data;

+ 1 - 1
src/SharpGLTF/Schema2/gltf.AccessorSparse.cs

@@ -89,7 +89,7 @@ namespace SharpGLTF.Schema2
         {
         {
             var view = root.LogicalBufferViews[this._bufferView];
             var view = root.LogicalBufferViews[this._bufferView];
             var info = new Geometry.MemoryAccessInfo(null, this._byteOffset ?? 0, count, view.ByteStride, baseAccessor.Dimensions, baseAccessor.Encoding, baseAccessor.Normalized);
             var info = new Geometry.MemoryAccessInfo(null, this._byteOffset ?? 0, count, view.ByteStride, baseAccessor.Dimensions, baseAccessor.Encoding, baseAccessor.Normalized);
-            return new Geometry.MemoryAccessor(info, view.Content);
+            return new Geometry.MemoryAccessor(view.Content, info);
         }
         }
     }
     }
 }
 }

+ 1 - 1
src/SharpGLTF/Schema2/gltf.Accessors.cs

@@ -81,7 +81,7 @@ namespace SharpGLTF.Schema2
         {
         {
             var view = SourceBufferView;
             var view = SourceBufferView;
             var info = new Geometry.MemoryAccessInfo(null, ByteOffset, Count, view.ByteStride, Dimensions, Encoding, Normalized);
             var info = new Geometry.MemoryAccessInfo(null, ByteOffset, Count, view.ByteStride, Dimensions, Encoding, Normalized);
-            return new Geometry.MemoryAccessor(info, view.Content);
+            return new Geometry.MemoryAccessor(view.Content, info);
         }
         }
 
 
         internal KeyValuePair<Memory.IntegerArray, Geometry.MemoryAccessor>? _GetSparseMemoryAccessor()
         internal KeyValuePair<Memory.IntegerArray, Geometry.MemoryAccessor>? _GetSparseMemoryAccessor()

+ 21 - 20
tests/SharpGLTF.Tests/Schema2/Authoring/CreateModelTests.cs

@@ -10,8 +10,9 @@ namespace SharpGLTF.Schema2.Authoring
 {
 {
     using Geometry;
     using Geometry;
 
 
-    using STATICVERTEX = Geometry.VertexTypes.StaticPositionNormal;
-    using SKINNEDVERTEX = Geometry.VertexTypes.SkinnedPosition;
+    using STATICVERTEX = Geometry.VertexTypes.VertexPositionNormal;
+    using VPOS = Geometry.VertexTypes.VertexPosition;
+    using SKIN4 = Geometry.VertexTypes.SkinJoints4;
 
 
     [TestFixture]
     [TestFixture]
     public class CreateModelTests
     public class CreateModelTests
@@ -243,7 +244,7 @@ namespace SharpGLTF.Schema2.Authoring
             TestContext.CurrentContext.AttachShowDirLink();
             TestContext.CurrentContext.AttachShowDirLink();
             TestContext.CurrentContext.AttachGltfValidatorLink();
             TestContext.CurrentContext.AttachGltfValidatorLink();
 
 
-            var meshBuilder = new InterleavedMeshBuilder<STATICVERTEX, Vector4>();
+            var meshBuilder = new StaticMeshBuilder<STATICVERTEX, Vector4>("mesh1");
 
 
             var v1 = new STATICVERTEX(-10, 10, 0, -10, 10, 15);
             var v1 = new STATICVERTEX(-10, 10, 0, -10, 10, 15);
             var v2 = new STATICVERTEX( 10, 10, 0, 10, 10, 15);
             var v2 = new STATICVERTEX( 10, 10, 0, 10, 10, 15);
@@ -261,7 +262,7 @@ namespace SharpGLTF.Schema2.Authoring
 
 
             model
             model
                 .UseScene("Default")
                 .UseScene("Default")
-                .CreateNode("RootNode").WithMesh( model.CreateMesh("mesh",meshBuilder, createMaterialForColor));
+                .CreateNode("RootNode").WithMesh( model.CreateMesh(createMaterialForColor, meshBuilder));
 
 
             model.AttachToCurrentTest("result.glb");
             model.AttachToCurrentTest("result.glb");
             model.AttachToCurrentTest("result.gltf");
             model.AttachToCurrentTest("result.gltf");
@@ -283,7 +284,7 @@ namespace SharpGLTF.Schema2.Authoring
             };
             };
 
 
             // create a mesh
             // create a mesh
-            var meshBuilder = new InterleavedMeshBuilder<STATICVERTEX, Vector4>();
+            var meshBuilder = new StaticMeshBuilder<STATICVERTEX, Vector4>("mesh1");
 
 
             var v1 = new STATICVERTEX(-10, 10, 0, -10, 10, 15);
             var v1 = new STATICVERTEX(-10, 10, 0, -10, 10, 15);
             var v2 = new STATICVERTEX(10, 10, 0, 10, 10, 15);
             var v2 = new STATICVERTEX(10, 10, 0, 10, 10, 15);
@@ -303,7 +304,7 @@ namespace SharpGLTF.Schema2.Authoring
             model.UseScene("Default")
             model.UseScene("Default")
                 .CreateNode("RootNode")
                 .CreateNode("RootNode")
                 .WithTranslationAnimation("track1", keyframes)
                 .WithTranslationAnimation("track1", keyframes)
-                .WithMesh(model.CreateMesh("mesh", meshBuilder, createMaterialForColor));
+                .WithMesh(model.CreateMesh(createMaterialForColor, meshBuilder));
 
 
             model.AttachToCurrentTest("result.glb");
             model.AttachToCurrentTest("result.glb");
             model.AttachToCurrentTest("result.gltf");
             model.AttachToCurrentTest("result.gltf");
@@ -343,22 +344,22 @@ namespace SharpGLTF.Schema2.Authoring
             snode.Skin.BindJoints(joint1, joint2, joint3);
             snode.Skin.BindJoints(joint1, joint2, joint3);
 
 
             // create the mesh
             // create the mesh
-            var meshBuilder = new InterleavedMeshBuilder<SKINNEDVERTEX, Vector4>();
+            var meshBuilder = new SkinnedMeshBuilder<VPOS, SKIN4, Vector4>("mesh1");
 
 
-            var v1 = new SKINNEDVERTEX(-10, 0, +10, 0);
-            var v2 = new SKINNEDVERTEX(+10, 0, +10, 0);
-            var v3 = new SKINNEDVERTEX(+10, 0, -10, 0);
-            var v4 = new SKINNEDVERTEX(-10, 0, -10, 0);
+            var v1 = (new VPOS(-10, 0, +10), new SKIN4(0));
+            var v2 = (new VPOS(+10, 0, +10), new SKIN4(0));
+            var v3 = (new VPOS(+10, 0, -10), new SKIN4(0));
+            var v4 = (new VPOS(-10, 0, -10), new SKIN4(0));
 
 
-            var v5 = new SKINNEDVERTEX(-10, 40, +10, 0, 1);
-            var v6 = new SKINNEDVERTEX(+10, 40, +10, 0, 1);
-            var v7 = new SKINNEDVERTEX(+10, 40, -10, 0, 1);
-            var v8 = new SKINNEDVERTEX(-10, 40, -10, 0, 1);
+            var v5 = (new VPOS(-10, 40, +10), new SKIN4(0, 1));
+            var v6 = (new VPOS(+10, 40, +10), new SKIN4(0, 1));
+            var v7 = (new VPOS(+10, 40, -10), new SKIN4(0, 1));
+            var v8 = (new VPOS(-10, 40, -10), new SKIN4(0, 1));
 
 
-            var v9  = new SKINNEDVERTEX(-5, 80, +5, 2);
-            var v10 = new SKINNEDVERTEX(+5, 80, +5, 2);
-            var v11 = new SKINNEDVERTEX(+5, 80, -5, 2);
-            var v12 = new SKINNEDVERTEX(-5, 80, -5, 2);
+            var v9  = (new VPOS(-5, 80, +5), new SKIN4(2));
+            var v10 = (new VPOS(+5, 80, +5), new SKIN4(2));
+            var v11 = (new VPOS(+5, 80, -5), new SKIN4(2));
+            var v12 = (new VPOS(-5, 80, -5), new SKIN4(2));
 
 
             meshBuilder.AddPolygon(new Vector4(1, 0, 1, 1), v1, v2, v6, v5);
             meshBuilder.AddPolygon(new Vector4(1, 0, 1, 1), v1, v2, v6, v5);
             meshBuilder.AddPolygon(new Vector4(1, 0, 1, 1), v2, v3, v7, v6);
             meshBuilder.AddPolygon(new Vector4(1, 0, 1, 1), v2, v3, v7, v6);
@@ -376,7 +377,7 @@ namespace SharpGLTF.Schema2.Authoring
                 return model.CreateMaterial().WithDefault(color).WithDoubleSide(true);
                 return model.CreateMaterial().WithDefault(color).WithDoubleSide(true);
             };
             };
 
 
-            snode.WithMesh(model.CreateMesh("mesh", meshBuilder, createMaterialForColor));
+            snode.WithMesh(model.CreateMesh(createMaterialForColor, meshBuilder));
 
 
             model.AttachToCurrentTest("result.glb");
             model.AttachToCurrentTest("result.glb");
             model.AttachToCurrentTest("result.gltf");
             model.AttachToCurrentTest("result.gltf");

+ 17 - 23
tests/SharpGLTF.Tests/WavefrontWriter.cs

@@ -8,7 +8,7 @@ using static System.FormattableString;
 
 
 namespace SharpGLTF
 namespace SharpGLTF
 {
 {
-    using VERTEX = Geometry.VertexTypes.StaticPositionNormal;
+    using VERTEX = Geometry.VertexTypes.VertexPositionNormal;
     using MATERIAL = Vector4;
     using MATERIAL = Vector4;
 
 
     /// <summary>
     /// <summary>
@@ -18,7 +18,7 @@ namespace SharpGLTF
     {
     {
         #region data
         #region data
 
 
-        private readonly Geometry.InterleavedMeshBuilder<VERTEX, MATERIAL> _Mesh = new Geometry.InterleavedMeshBuilder<VERTEX, MATERIAL>();
+        private readonly Geometry.StaticMeshBuilder<VERTEX, MATERIAL> _Mesh = new Geometry.StaticMeshBuilder<VERTEX, MATERIAL>();
         
         
         #endregion
         #endregion
 
 
@@ -26,20 +26,9 @@ namespace SharpGLTF
 
 
         public void AddTriangle(Vector3 a, Vector3 b, Vector3 c)
         public void AddTriangle(Vector3 a, Vector3 b, Vector3 c)
         {
         {
-            var aa = new Geometry.VertexTypes.StaticPositionNormal
-            {
-                Position = a
-            };
-
-            var bb = new Geometry.VertexTypes.StaticPositionNormal
-            {
-                Position = b
-            };
-
-            var cc = new Geometry.VertexTypes.StaticPositionNormal
-            {
-                Position = c
-            };
+            var aa = new VERTEX { Position = a };
+            var bb = new VERTEX { Position = b };
+            var cc = new VERTEX { Position = c };
 
 
             _Mesh.AddTriangle(Vector4.One, aa, bb, cc);
             _Mesh.AddTriangle(Vector4.One, aa, bb, cc);
         }
         }
@@ -50,23 +39,28 @@ namespace SharpGLTF
 
 
             sb.AppendLine();
             sb.AppendLine();
 
 
-            foreach (var v in _Mesh.Vertices)
+            foreach (var p in _Mesh.Primitives)
             {
             {
-                sb.AppendLine(Invariant($"v {v.Position.X} {v.Position.Y} {v.Position.Z}"));
+                foreach (var v in p.Vertices)
+                {
+                    sb.AppendLine(Invariant($"v {v.Position.X} {v.Position.Y} {v.Position.Z}"));
+                }
             }
             }
 
 
             sb.AppendLine();
             sb.AppendLine();
 
 
             sb.AppendLine("g default");
             sb.AppendLine("g default");
 
 
-            foreach(var m in _Mesh.Materials)
-            {
-                var triangles = _Mesh.GetTriangles(m);
+            var baseVertexIndex = 1;
 
 
-                foreach (var t in triangles)
+            foreach(var p in _Mesh.Primitives)
+            {
+                foreach (var t in p.Triangles)
                 {
                 {
-                    sb.AppendLine(Invariant($"f {t.Item1 + 1} {t.Item2 + 1} {t.Item3 + 1}"));
+                    sb.AppendLine(Invariant($"f {t.Item1 + baseVertexIndex} {t.Item2 + baseVertexIndex} {t.Item3 + baseVertexIndex}"));
                 }
                 }
+
+                baseVertexIndex += p.Vertices.Count;
             }
             }
 
 
             return sb.ToString();
             return sb.ToString();