Просмотр исходного кода

refactored MeshBuilder to support multiple combinations of vertex flavours

Vicente Penades 6 лет назад
Родитель
Сommit
8b3aca703f
27 измененных файлов с 720 добавлено и 493 удалено
  1. 2 83
      src/Shared/_Extensions.cs
  2. 98 0
      src/SharpGLTF.Core/Schema2/_Extensions.cs
  3. 1 1
      src/SharpGLTF.Core/Schema2/gltf.AccessorSparse.cs
  4. 1 1
      src/SharpGLTF.Core/Schema2/gltf.Accessors.cs
  5. 1 1
      src/SharpGLTF.Core/Schema2/gltf.Camera.cs
  6. 1 1
      src/SharpGLTF.Core/Schema2/gltf.Materials.cs
  7. 2 2
      src/SharpGLTF.Core/Schema2/gltf.MaterialsFactory.cs
  8. 1 1
      src/SharpGLTF.Core/Schema2/gltf.Root.cs
  9. 1 0
      src/SharpGLTF.Core/SharpGLTF.Core.csproj
  10. 221 0
      src/SharpGLTF.Toolkit/Geometry/MeshBuilder.cs
  11. 13 3
      src/SharpGLTF.Toolkit/Geometry/PackedMeshBuilder.cs
  12. 0 143
      src/SharpGLTF.Toolkit/Geometry/SkinnedMeshBuilder.cs
  13. 11 17
      src/SharpGLTF.Toolkit/Geometry/StaticMeshBuilder.cs
  14. 0 65
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/SkinnedVertices.cs
  15. 0 79
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/StaticVertices.cs
  16. 11 0
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexEmpty.cs
  17. 79 0
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexJoints.cs
  18. 75 0
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexMaterial.cs
  19. 91 0
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexPosition.cs
  20. 41 48
      src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexUtils.cs
  21. 32 18
      src/SharpGLTF.Toolkit/Schema2/MeshExtensions.cs
  22. 1 0
      src/SharpGLTF.Toolkit/SharpGLTF.Toolkit.csproj
  23. 3 0
      tests/SharpGLTF.Tests/ExtensionsTests.cs
  24. 4 4
      tests/SharpGLTF.Tests/Memory/MemoryArrayTests.cs
  25. 19 15
      tests/SharpGLTF.Tests/Schema2/Authoring/CreateModelTests.cs
  26. 5 6
      tests/SharpGLTF.Tests/Schema2/Authoring/SolidMeshUtils.cs
  27. 6 5
      tests/SharpGLTF.Tests/WavefrontWriter.cs

+ 2 - 83
src/SharpGLTF.Core/_Extensions.cs → src/Shared/_Extensions.cs

@@ -71,19 +71,6 @@ namespace SharpGLTF
 
 
         #endregion
         #endregion
 
 
-        #region base64
-
-        internal static Byte[] _TryParseBase64Unchecked(this string uri, string prefix)
-        {
-            if (uri == null) return null;
-            if (!uri.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) return null;
-
-            var content = uri.Substring(prefix.Length);
-            return Convert.FromBase64String(content);
-        }
-
-        #endregion
-
         #region linq
         #region linq
 
 
         internal static ArraySegment<T> Slice<T>(this T[] array, int offset)
         internal static ArraySegment<T> Slice<T>(this T[] array, int offset)
@@ -206,74 +193,6 @@ namespace SharpGLTF
             }
             }
         }
         }
 
 
-        internal static T AsValue<T>(this T? value, T defval)
-            where T : struct
-        {
-            return value ?? defval;
-        }
-
-        internal static T? AsNullable<T>(this T value, T defval)
-            where T : struct
-        {
-            return value.Equals(defval) ? (T?)null : value;
-        }
-
-        internal static T? AsNullable<T>(this T value, T defval, T minval, T maxval)
-            where T : struct, IEquatable<T>, IComparable<T>
-        {
-            if (value.Equals(defval)) return null;
-
-            if (value.CompareTo(minval) < 0) value = minval;
-            if (value.CompareTo(maxval) > 0) value = maxval;
-
-            return value.Equals(defval) ? (T?)null : value;
-        }
-
-        internal static Vector2? AsNullable(this Vector2 value, Vector2 defval, Vector2 minval, Vector2 maxval)
-        {
-            if (value.Equals(defval)) return null;
-
-            value = Vector2.Min(value, minval);
-            value = Vector2.Max(value, maxval);
-
-            return value.Equals(defval) ? (Vector2?)null : value;
-        }
-
-        internal static Vector3? AsNullable(this Vector3 value, Vector3 defval, Vector3 minval, Vector3 maxval)
-        {
-            if (value.Equals(defval)) return null;
-
-            value = Vector3.Min(value, minval);
-            value = Vector3.Max(value, maxval);
-
-            return value.Equals(defval) ? (Vector3?)null : value;
-        }
-
-        internal static Vector4? AsNullable(this Vector4 value, Vector4 defval, Vector4 minval, Vector4 maxval)
-        {
-            if (value.Equals(defval)) return (Vector4?)null;
-
-            value = Vector4.Min(value, minval);
-            value = Vector4.Max(value, maxval);
-
-            return value.Equals(defval) ? (Vector4?)null : value;
-        }
-
-        internal static String AsNullable(this string value)
-        {
-            return string.IsNullOrEmpty(value) ? null : value;
-        }
-
-        internal static String AsEmptyNullable(this string value)
-        {
-            return string.IsNullOrWhiteSpace(value) ? null : value;
-        }
-
-        internal static String AsName(this string name)
-        {
-            return string.IsNullOrWhiteSpace(name) ? null : name;
-        }
-
         internal static void AddRange<Tin, Tout>(this IList<Tout> dst, IEnumerable<Tin> src, Func<Tin, Tout> cvt)
         internal static void AddRange<Tin, Tout>(this IList<Tout> dst, IEnumerable<Tin> src, Func<Tin, Tout> cvt)
         {
         {
             foreach (var item in src)
             foreach (var item in src)
@@ -282,12 +201,12 @@ namespace SharpGLTF
             }
             }
         }
         }
 
 
-        internal static IEnumerable<T> Concat<T>(this IEnumerable<T> collection, params T[] instances)
+        internal static IEnumerable<T> ConcatItems<T>(this IEnumerable<T> collection, params T[] instances)
         {
         {
             return collection.Concat(instances.Where(item => item != null));
             return collection.Concat(instances.Where(item => item != null));
         }
         }
 
 
-        #endregion
+        #endregion        
 
 
         #region vertex & index accessors
         #region vertex & index accessors
 
 

+ 98 - 0
src/SharpGLTF.Core/Schema2/_Extensions.cs

@@ -0,0 +1,98 @@
+using System;
+using System.Collections.Generic;
+using System.Numerics;
+using System.Text;
+
+namespace SharpGLTF.Schema2
+{
+    /// <summary>
+    /// Extensions used internally.
+    /// </summary>
+    static class _Schema2Extensions
+    {
+        #region base64
+
+        internal static Byte[] _TryParseBase64Unchecked(this string uri, string prefix)
+        {
+            if (uri == null) return null;
+            if (!uri.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) return null;
+
+            var content = uri.Substring(prefix.Length);
+            return Convert.FromBase64String(content);
+        }
+
+        #endregion
+
+        #region nullables
+
+        internal static String AsName(this string name)
+        {
+            return string.IsNullOrWhiteSpace(name) ? null : name;
+        }
+
+        internal static T AsValue<T>(this T? value, T defval)
+            where T : struct
+        {
+            return value ?? defval;
+        }
+
+        internal static T? AsNullable<T>(this T value, T defval)
+            where T : struct
+        {
+            return value.Equals(defval) ? (T?)null : value;
+        }
+
+        internal static T? AsNullable<T>(this T value, T defval, T minval, T maxval)
+            where T : struct, IEquatable<T>, IComparable<T>
+        {
+            if (value.Equals(defval)) return null;
+
+            if (value.CompareTo(minval) < 0) value = minval;
+            if (value.CompareTo(maxval) > 0) value = maxval;
+
+            return value.Equals(defval) ? (T?)null : value;
+        }
+
+        internal static Vector2? AsNullable(this Vector2 value, Vector2 defval, Vector2 minval, Vector2 maxval)
+        {
+            if (value.Equals(defval)) return null;
+
+            value = Vector2.Min(value, minval);
+            value = Vector2.Max(value, maxval);
+
+            return value.Equals(defval) ? (Vector2?)null : value;
+        }
+
+        internal static Vector3? AsNullable(this Vector3 value, Vector3 defval, Vector3 minval, Vector3 maxval)
+        {
+            if (value.Equals(defval)) return null;
+
+            value = Vector3.Min(value, minval);
+            value = Vector3.Max(value, maxval);
+
+            return value.Equals(defval) ? (Vector3?)null : value;
+        }
+
+        internal static Vector4? AsNullable(this Vector4 value, Vector4 defval, Vector4 minval, Vector4 maxval)
+        {
+            if (value.Equals(defval)) return (Vector4?)null;
+
+            value = Vector4.Min(value, minval);
+            value = Vector4.Max(value, maxval);
+
+            return value.Equals(defval) ? (Vector4?)null : value;
+        }
+
+        internal static String AsNullable(this string value)
+        {
+            return string.IsNullOrEmpty(value) ? null : value;
+        }
+
+        internal static String AsEmptyNullable(this string value)
+        {
+            return string.IsNullOrWhiteSpace(value) ? null : value;
+        }
+
+        #endregion
+    }
+}

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

@@ -23,7 +23,7 @@ namespace SharpGLTF.Schema2
         /// <inheritdoc />
         /// <inheritdoc />
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         {
         {
-            return base.GetLogicalChildren().Concat(_indices, _values);
+            return base.GetLogicalChildren().ConcatItems(_indices, _values);
         }
         }
 
 
         internal AccessorSparse(BufferView indices, int indicesOffset, IndexEncodingType indicesEncoding, BufferView values, int valuesOffset, int count)
         internal AccessorSparse(BufferView indices, int indicesOffset, IndexEncodingType indicesEncoding, BufferView values, int valuesOffset, int count)

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

@@ -286,7 +286,7 @@ namespace SharpGLTF.Schema2
 
 
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         {
         {
-            return base.GetLogicalChildren().Concat(_sparse);
+            return base.GetLogicalChildren().ConcatItems(_sparse);
         }
         }
 
 
         public void UpdateBounds()
         public void UpdateBounds()

+ 1 - 1
src/SharpGLTF.Core/Schema2/gltf.Camera.cs

@@ -33,7 +33,7 @@ namespace SharpGLTF.Schema2
         /// <inheritdoc />
         /// <inheritdoc />
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         {
         {
-            return base.GetLogicalChildren().Concat(_orthographic, _perspective);
+            return base.GetLogicalChildren().ConcatItems(_orthographic, _perspective);
         }
         }
 
 
         #endregion
         #endregion

+ 1 - 1
src/SharpGLTF.Core/Schema2/gltf.Materials.cs

@@ -66,7 +66,7 @@ namespace SharpGLTF.Schema2
         /// <inheritdoc />
         /// <inheritdoc />
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         {
         {
-            return base.GetLogicalChildren().Concat(_normalTexture, _emissiveTexture, _occlusionTexture, _pbrMetallicRoughness);
+            return base.GetLogicalChildren().ConcatItems(_normalTexture, _emissiveTexture, _occlusionTexture, _pbrMetallicRoughness);
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 2 - 2
src/SharpGLTF.Core/Schema2/gltf.MaterialsFactory.cs

@@ -108,7 +108,7 @@ namespace SharpGLTF.Schema2
         /// <inheritdoc />
         /// <inheritdoc />
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         {
         {
-            return base.GetLogicalChildren().Concat(_baseColorTexture, _metallicRoughnessTexture);
+            return base.GetLogicalChildren().ConcatItems(_baseColorTexture, _metallicRoughnessTexture);
         }
         }
 
 
         private TextureInfo _GetBaseTexture(bool create)
         private TextureInfo _GetBaseTexture(bool create)
@@ -161,7 +161,7 @@ namespace SharpGLTF.Schema2
         /// <inheritdoc />
         /// <inheritdoc />
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         protected override IEnumerable<ExtraProperties> GetLogicalChildren()
         {
         {
-            return base.GetLogicalChildren().Concat(_diffuseTexture, _specularGlossinessTexture);
+            return base.GetLogicalChildren().ConcatItems(_diffuseTexture, _specularGlossinessTexture);
         }
         }
 
 
         private TextureInfo _GetDiffuseTexture(bool create)
         private TextureInfo _GetDiffuseTexture(bool create)

+ 1 - 1
src/SharpGLTF.Core/Schema2/gltf.Root.cs

@@ -99,7 +99,7 @@ namespace SharpGLTF.Schema2
         {
         {
             var containers = base.GetLogicalChildren();
             var containers = base.GetLogicalChildren();
 
 
-            containers = containers.Concat(this.Asset);
+            containers = containers.ConcatItems(this.Asset);
             containers = containers.Concat(this.LogicalAccessors);
             containers = containers.Concat(this.LogicalAccessors);
             containers = containers.Concat(this.LogicalAnimations);
             containers = containers.Concat(this.LogicalAnimations);
             containers = containers.Concat(this.LogicalBuffers);
             containers = containers.Concat(this.LogicalBuffers);

+ 1 - 0
src/SharpGLTF.Core/SharpGLTF.Core.csproj

@@ -26,6 +26,7 @@
 
 
   <ItemGroup>
   <ItemGroup>
     <Compile Include="..\Shared\Guard.cs" Link="Debug\Guard.cs" />
     <Compile Include="..\Shared\Guard.cs" Link="Debug\Guard.cs" />
+    <Compile Include="..\Shared\_Extensions.cs" Link="_Extensions.cs" />
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup>
   <ItemGroup>

+ 221 - 0
src/SharpGLTF.Toolkit/Geometry/MeshBuilder.cs

@@ -0,0 +1,221 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Linq;
+
+namespace SharpGLTF.Geometry
+{
+    using Collections;
+
+    public class PrimitiveBuilder<TMaterial, TvP, TvM, TvJ>
+        where TvP : struct, VertexTypes.IVertexPosition
+        where TvM : struct, VertexTypes.IVertexMaterial
+        where TvJ : struct, VertexTypes.IVertexJoints
+    {
+        #region lifecycle
+
+        internal PrimitiveBuilder(MeshBuilder<TMaterial, TvP, TvM, TvJ> mesh, TMaterial material, bool strict)
+        {
+            this._Scrict = strict;
+            this._Mesh = mesh;
+            this._Material = material;
+        }
+
+        #endregion
+
+        #region data
+
+        private readonly bool _Scrict;
+
+        private readonly MeshBuilder<TMaterial, TvP, TvM, TvJ> _Mesh;
+
+        private readonly TMaterial _Material;
+
+        private readonly VertexColumn<(TvP, TvM, TvJ)> _Vertices = new VertexColumn<(TvP, TvM, TvJ)>();
+        private readonly List<int> _Indices = new List<int>();
+
+        #endregion
+
+        #region properties
+
+        public MeshBuilder<TMaterial, TvP, TvM, TvJ> Mesh => _Mesh;
+
+        public TMaterial Material => _Material;
+
+        public IReadOnlyList<(TvP, TvM, TvJ)> 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 int UseVertex((TvP, TvM, TvJ) vertex)
+        {
+            if (_Scrict)
+            {
+                vertex.Item1.Validate();
+                vertex.Item2.Validate();
+                vertex.Item3.Validate();
+            }
+
+            return _Vertices.Use(vertex);
+        }
+
+        public void AddTriangle((TvP, TvM, TvJ) a, (TvP, TvM, TvJ) b, (TvP, TvM, TvJ) c)
+        {
+            var aa = UseVertex(a);
+            var bb = UseVertex(b);
+            var cc = UseVertex(c);
+
+            // check for degenerated triangles:
+            if (aa == bb || aa == cc || bb == cc)
+            {
+                if (_Scrict) throw new ArgumentException($"Invalid triangle {aa} {bb} {cc}");
+                return;
+            }
+
+            _Indices.Add(aa);
+            _Indices.Add(bb);
+            _Indices.Add(cc);
+        }
+
+        public void Validate()
+        {
+            foreach (var v in _Vertices)
+            {
+                v.Item1.Validate();
+                v.Item2.Validate();
+                v.Item3.Validate();
+            }
+        }
+
+        #endregion
+    }
+
+    public class MeshBuilder<TMaterial, TvP, TvM, TvJ>
+        where TvP : struct, VertexTypes.IVertexPosition
+        where TvM : struct, VertexTypes.IVertexMaterial
+        where TvJ : struct, VertexTypes.IVertexJoints
+    {
+        #region lifecycle
+
+        public MeshBuilder(string name = null)
+        {
+            this.Name = name;
+        }
+
+        #endregion
+
+        #region data
+
+        private readonly Dictionary<TMaterial, PrimitiveBuilder<TMaterial, TvP, TvM, TvJ>> _Primitives = new Dictionary<TMaterial, PrimitiveBuilder<TMaterial, TvP, TvM, TvJ>>();
+
+        #endregion
+
+        #region properties
+
+        public Boolean StrictMode { get; set; }
+
+        public string Name { get; set; }
+
+        public IReadOnlyCollection<PrimitiveBuilder<TMaterial, TvP, TvM, TvJ>> Primitives => _Primitives.Values;
+
+        #endregion
+
+        #region API
+
+        public void AddPolygon(TMaterial material, params (TvP, TvM, TvJ)[] points)
+        {
+            for (int i = 2; i < points.Length; ++i)
+            {
+                AddTriangle(material, points[0], points[i - 1], points[i]);
+            }
+        }
+
+        public void AddPolygon(TMaterial material, params (TvP, TvM)[] points)
+        {
+            for (int i = 2; i < points.Length; ++i)
+            {
+                AddTriangle(material, points[0], points[i - 1], points[i]);
+            }
+        }
+
+        public void AddPolygon(TMaterial material, params (TvP, TvJ)[] points)
+        {
+            for (int i = 2; i < points.Length; ++i)
+            {
+                AddTriangle(material, points[0], points[i - 1], points[i]);
+            }
+        }
+
+        public void AddPolygon(TMaterial material, params TvP[] points)
+        {
+            for (int i = 2; i < points.Length; ++i)
+            {
+                AddTriangle(material, points[0], points[i - 1], points[i]);
+            }
+        }
+
+        public void AddTriangle(TMaterial material, (TvP, TvM, TvJ) a, (TvP, TvM, TvJ) b, (TvP, TvM, TvJ) c)
+        {
+            if (!_Primitives.TryGetValue(material, out PrimitiveBuilder<TMaterial, TvP, TvM, TvJ> primitive))
+            {
+                primitive = new PrimitiveBuilder<TMaterial, TvP, TvM, TvJ>(this, material, StrictMode);
+                _Primitives[material] = primitive;
+            }
+
+            primitive.AddTriangle(a, b, c);
+        }
+
+        public void AddTriangle(TMaterial material, (TvP, TvM) a, (TvP, TvM) b, (TvP, TvM) c)
+        {
+            AddTriangle(material, (a.Item1, a.Item2, default), (b.Item1, b.Item2, default), (c.Item1, c.Item2, default));
+        }
+
+        public void AddTriangle(TMaterial material, (TvP, TvJ) a, (TvP, TvJ) b, (TvP, TvJ) c)
+        {
+            AddTriangle(material, (a.Item1, default, a.Item2), (b.Item1, default, b.Item2), (c.Item1, default, c.Item2));
+        }
+
+        public void AddTriangle(TMaterial material, TvP a, TvP b, TvP c)
+        {
+            AddTriangle(material, (a, default, default), (b, default, default), (c, default, default));
+        }
+
+        public IEnumerable<(int, int, int)> GetTriangles(TMaterial material)
+        {
+            if (_Primitives.TryGetValue(material, out PrimitiveBuilder<TMaterial, TvP, TvM, TvJ> primitive)) return primitive.Triangles;
+
+            return Enumerable.Empty<(int, int, int)>();
+        }
+
+        public IReadOnlyList<int> GetIndices(TMaterial material)
+        {
+            if (_Primitives.TryGetValue(material, out PrimitiveBuilder<TMaterial, TvP, TvM, TvJ> primitive)) return primitive.Indices;
+
+            return new int[0];
+        }
+
+        public void Validate()
+        {
+            foreach (var p in _Primitives.Values)
+            {
+                p.Validate();
+            }
+        }
+
+        #endregion
+    }
+}

+ 13 - 3
src/SharpGLTF.Toolkit/Geometry/PackedMeshBuilder.cs

@@ -11,10 +11,20 @@ namespace SharpGLTF.Geometry
     {
     {
         #region lifecycle
         #region lifecycle
 
 
-        internal static IEnumerable<PackedMeshBuilder<TMaterial>> PackMeshes<TVertex, TJoints>(IEnumerable<SkinnedMeshBuilder<TMaterial, TVertex, TJoints>> meshBuilders)
-            where TVertex : struct, VertexTypes.IVertex
-            where TJoints : struct, VertexTypes.IJoints
+        internal static IEnumerable<PackedMeshBuilder<TMaterial>> PackMeshes<TvP, TvM, TvJ>(IEnumerable<MeshBuilder<TMaterial, TvP, TvM, TvJ>> meshBuilders)
+            where TvP : struct, VertexTypes.IVertexPosition
+            where TvM : struct, VertexTypes.IVertexMaterial
+            where TvJ : struct, VertexTypes.IVertexJoints
         {
         {
+            try
+            {
+                foreach (var m in meshBuilders) m.Validate();
+            }
+            catch(Exception ex)
+            {
+                throw new ArgumentException(ex.Message, nameof(meshBuilders), ex);
+            }
+
             var vertexBlocks = VertexTypes.VertexUtils.CreateVertexMemoryAccessors
             var vertexBlocks = VertexTypes.VertexUtils.CreateVertexMemoryAccessors
                 (
                 (
                 meshBuilders
                 meshBuilders

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

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

+ 11 - 17
src/SharpGLTF.Toolkit/Geometry/StaticMeshBuilder.cs

@@ -6,24 +6,18 @@ using System.Text;
 
 
 namespace SharpGLTF.Geometry
 namespace SharpGLTF.Geometry
 {
 {
-    using Collections;
-
-    public class StaticMeshBuilder<TMaterial, TVertex> : SkinnedMeshBuilder<TMaterial, TVertex, VertexTypes.VertexJoints0>
-        where TVertex : struct, VertexTypes.IVertex
+    public class MeshBuilder<TMaterial, TVertex, TValues> : MeshBuilder<TMaterial, TVertex, TValues, VertexTypes.VertexEmpty>
+        where TVertex : struct, VertexTypes.IVertexPosition
+        where TValues : struct, VertexTypes.IVertexMaterial
     {
     {
-        public StaticMeshBuilder(string name = null) : base(name) { }
-
-        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 MeshBuilder(string name = null)
+            : base(name) { }
+    }
 
 
-        public new void AddTriangle(TMaterial material, TVertex a, TVertex b, TVertex c)
-        {
-            AddTriangle(material, (a, default), (b, default), (c, default));
-        }
+    public class MeshBuilder<TMaterial, TVertex> : MeshBuilder<TMaterial, TVertex, VertexTypes.VertexEmpty, VertexTypes.VertexEmpty>
+       where TVertex : struct, VertexTypes.IVertexPosition
+    {
+        public MeshBuilder(string name = null)
+            : base(name) { }
     }
     }
 }
 }

+ 0 - 65
src/SharpGLTF.Toolkit/Geometry/VertexTypes/SkinnedVertices.cs

@@ -1,65 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Numerics;
-using System.Text;
-
-namespace SharpGLTF.Geometry.VertexTypes
-{
-    public interface IJoints { }
-
-    public struct VertexJoints0 : IJoints
-    {
-    }
-
-    public struct VertexJoints4 : IJoints
-    {
-        public VertexJoints4(int jointIndex)
-        {
-            Joints_0 = new Vector4(jointIndex);
-            Weights_0 = Vector4.UnitX;
-        }
-
-        public VertexJoints4(int jointIndex1, int jointIndex2)
-        {
-            Joints_0 = new Vector4(jointIndex1, jointIndex2, 0, 0);
-            Weights_0 = new Vector4(0.5f, 0.5f, 0, 0);
-        }
-
-        [VertexAttribute("JOINTS_0", Schema2.EncodingType.UNSIGNED_BYTE, false)]
-        public Vector4 Joints_0;
-
-        [VertexAttribute("WEIGHTS_0", Schema2.EncodingType.UNSIGNED_BYTE, true)]
-        public Vector4 Weights_0;
-    }
-
-    public struct VertexJoints8 : IJoints
-    {
-        public VertexJoints8(int jointIndex)
-        {
-            Joints_0 = new Vector4(jointIndex);
-            Joints_1 = new Vector4(jointIndex);
-            Weights_0 = Vector4.UnitX;
-            Weights_1 = Vector4.Zero;
-        }
-
-        public VertexJoints8(int jointIndex1, int jointIndex2)
-        {
-            Joints_0 = new Vector4(jointIndex1, jointIndex2, 0, 0);
-            Joints_1 = Vector4.Zero;
-            Weights_0 = new Vector4(0.5f, 0.5f, 0, 0);
-            Weights_1 = Vector4.Zero;
-        }
-
-        [VertexAttribute("JOINTS_0", Schema2.EncodingType.UNSIGNED_BYTE, false)]
-        public Vector4 Joints_0;
-
-        [VertexAttribute("JOINTS_1", Schema2.EncodingType.UNSIGNED_BYTE, false)]
-        public Vector4 Joints_1;
-
-        [VertexAttribute("WEIGHTS_0", Schema2.EncodingType.UNSIGNED_BYTE, true)]
-        public Vector4 Weights_0;
-
-        [VertexAttribute("WEIGHTS_1", Schema2.EncodingType.UNSIGNED_BYTE, true)]
-        public Vector4 Weights_1;
-    }
-}

+ 0 - 79
src/SharpGLTF.Toolkit/Geometry/VertexTypes/StaticVertices.cs

@@ -1,79 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Numerics;
-using System.Text;
-
-namespace SharpGLTF.Geometry.VertexTypes
-{
-    public interface IVertex { }
-
-    public struct VertexPosition : IVertex
-    {
-        public VertexPosition(float px, float py, float pz)
-        {
-            Position = new Vector3(px, py, pz);
-        }
-
-        [VertexAttribute("POSITION")]
-        public Vector3 Position;
-    }
-
-    public struct VertexPositionNormal : IVertex
-    {
-        public VertexPositionNormal(Vector3 p, Vector3 n)
-        {
-            Position = p;
-            Normal = Vector3.Normalize(n);
-        }
-
-        public VertexPositionNormal(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));
-        }
-
-        [VertexAttribute("POSITION")]
-        public Vector3 Position;
-
-        [VertexAttribute("NORMAL")]
-        public Vector3 Normal;
-    }
-
-    public struct VertexPositionNormalColor1 : IVertex
-    {
-        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 VertexPositionNormalTexture1 : IVertex
-    {
-        public VertexPositionNormalTexture1(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;
-    }
-}

+ 11 - 0
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexEmpty.cs

@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace SharpGLTF.Geometry.VertexTypes
+{
+    public struct VertexEmpty : IVertexMaterial, IVertexJoints
+    {
+        public void Validate() { }
+    }
+}

+ 79 - 0
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexJoints.cs

@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.Numerics;
+using System.Text;
+
+namespace SharpGLTF.Geometry.VertexTypes
+{
+    public interface IVertexJoints
+    {
+        void Validate();
+    }
+
+    public struct VertexJoints4 : IVertexJoints
+    {
+        public VertexJoints4(int jointIndex)
+        {
+            Joints = new Vector4(jointIndex);
+            Weights = Vector4.UnitX;
+        }
+
+        public VertexJoints4(int jointIndex1, int jointIndex2)
+        {
+            Joints = new Vector4(jointIndex1, jointIndex2, 0, 0);
+            Weights = new Vector4(0.5f, 0.5f, 0, 0);
+        }
+
+        [VertexAttribute("JOINTS_0", Schema2.EncodingType.UNSIGNED_BYTE, false)]
+        public Vector4 Joints;
+
+        [VertexAttribute("WEIGHTS_0", Schema2.EncodingType.UNSIGNED_BYTE, true)]
+        public Vector4 Weights;
+
+        public void Validate()
+        {
+            if (!Joints._IsReal()) throw new NotFiniteNumberException(nameof(Joints));
+            if (!Weights._IsReal()) throw new NotFiniteNumberException(nameof(Weights));
+        }
+    }
+
+    public struct VertexJoints8 : IVertexJoints
+    {
+        public VertexJoints8(int jointIndex)
+        {
+            Joints0 = new Vector4(jointIndex);
+            Joints1 = new Vector4(jointIndex);
+            Weights0 = Vector4.UnitX;
+            Weights1 = Vector4.Zero;
+        }
+
+        public VertexJoints8(int jointIndex1, int jointIndex2)
+        {
+            Joints0 = new Vector4(jointIndex1, jointIndex2, 0, 0);
+            Joints1 = Vector4.Zero;
+            Weights0 = new Vector4(0.5f, 0.5f, 0, 0);
+            Weights1 = Vector4.Zero;
+        }
+
+        [VertexAttribute("JOINTS_0", Schema2.EncodingType.UNSIGNED_BYTE, false)]
+        public Vector4 Joints0;
+
+        [VertexAttribute("JOINTS_1", Schema2.EncodingType.UNSIGNED_BYTE, false)]
+        public Vector4 Joints1;
+
+        [VertexAttribute("WEIGHTS_0", Schema2.EncodingType.UNSIGNED_BYTE, true)]
+        public Vector4 Weights0;
+
+        [VertexAttribute("WEIGHTS_1", Schema2.EncodingType.UNSIGNED_BYTE, true)]
+        public Vector4 Weights1;
+
+        public void Validate()
+        {
+            if (!Joints0._IsReal()) throw new NotFiniteNumberException(nameof(Joints0));
+            if (!Joints1._IsReal()) throw new NotFiniteNumberException(nameof(Joints1));
+
+            if (!Weights0._IsReal()) throw new NotFiniteNumberException(nameof(Weights0));
+            if (!Weights1._IsReal()) throw new NotFiniteNumberException(nameof(Weights1));
+        }
+    }
+}

+ 75 - 0
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexMaterial.cs

@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using System.Numerics;
+using System.Text;
+
+namespace SharpGLTF.Geometry.VertexTypes
+{
+    public interface IVertexMaterial
+    {
+        void Validate();
+    }
+
+    public struct VertexColor1 : IVertexMaterial
+    {
+        public VertexColor1(Vector4 color)
+        {
+            Color = color;
+        }
+
+        public static implicit operator VertexColor1(Vector4 color)
+        {
+            return new VertexColor1(color);
+        }
+
+        [VertexAttribute("COLOR_0", Schema2.EncodingType.UNSIGNED_BYTE, true)]
+        public Vector4 Color;
+
+        public void Validate()
+        {
+            if (!Color._IsReal()) throw new NotFiniteNumberException(nameof(Color));
+        }
+    }
+
+    public struct VertexTexture1 : IVertexMaterial
+    {
+        public VertexTexture1(Vector2 uv)
+        {
+            TexCoord = uv;
+        }
+
+        public static implicit operator VertexTexture1(Vector2 uv)
+        {
+            return new VertexTexture1(uv);
+        }
+
+        [VertexAttribute("TEXCOORD_0")]
+        public Vector2 TexCoord;
+
+        public void Validate()
+        {
+            if (!TexCoord._IsReal()) throw new NotFiniteNumberException(nameof(TexCoord));
+        }
+    }
+
+    public struct VertexColor1Texture1 : IVertexMaterial
+    {
+        public VertexColor1Texture1(Vector4 color, Vector2 tex)
+        {
+            Color = color;
+            TexCoord = tex;
+        }
+
+        [VertexAttribute("COLOR_0", Schema2.EncodingType.UNSIGNED_BYTE, true)]
+        public Vector4 Color;
+
+        [VertexAttribute("TEXCOORD_0")]
+        public Vector2 TexCoord;
+
+        public void Validate()
+        {
+            if (!Color._IsReal()) throw new NotFiniteNumberException(nameof(Color));
+            if (!TexCoord._IsReal()) throw new NotFiniteNumberException(nameof(TexCoord));
+        }
+    }
+}

+ 91 - 0
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexPosition.cs

@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Numerics;
+using System.Text;
+
+namespace SharpGLTF.Geometry.VertexTypes
+{
+    public interface IVertexPosition
+    {
+        void Validate();
+    }
+
+    public struct VertexPosition : IVertexPosition
+    {
+        public VertexPosition(Vector3 position)
+        {
+            this.Position = position;
+        }
+
+        public VertexPosition(float px, float py, float pz)
+        {
+            this.Position = new Vector3(px, py, pz);
+        }
+
+        public static implicit operator VertexPosition(Vector3 position)
+        {
+            return new VertexPosition(position);
+        }
+
+        [VertexAttribute("POSITION")]
+        public Vector3 Position;
+
+        public void Validate()
+        {
+            if (!Position._IsReal()) throw new NotFiniteNumberException(nameof(Position));
+        }
+    }
+
+    public struct VertexPositionNormal : IVertexPosition
+    {
+        public VertexPositionNormal(Vector3 p, Vector3 n)
+        {
+            Position = p;
+            Normal = Vector3.Normalize(n);
+        }
+
+        public VertexPositionNormal(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));
+        }
+
+        [VertexAttribute("POSITION")]
+        public Vector3 Position;
+
+        [VertexAttribute("NORMAL")]
+        public Vector3 Normal;
+
+        public void Validate()
+        {
+            if (!Position._IsReal()) throw new NotFiniteNumberException(nameof(Position));
+            if (!Normal._IsReal()) throw new NotFiniteNumberException(nameof(Normal));
+        }
+    }
+
+    public struct VertexPositionNormalTangent : IVertexPosition
+    {
+        public VertexPositionNormalTangent(Vector3 p, Vector3 n, Vector4 t)
+        {
+            Position = p;
+            Normal = Vector3.Normalize(n);
+            Tangent = t;
+        }
+
+        [VertexAttribute("POSITION")]
+        public Vector3 Position;
+
+        [VertexAttribute("NORMAL")]
+        public Vector3 Normal;
+
+        [VertexAttribute("TANGENT")]
+        public Vector4 Tangent;
+
+        public void Validate()
+        {
+            if (!Position._IsReal()) throw new NotFiniteNumberException(nameof(Position));
+            if (!Normal._IsReal()) throw new NotFiniteNumberException(nameof(Normal));
+            if (!Tangent._IsReal()) throw new NotFiniteNumberException(nameof(Tangent));
+        }
+    }
+}

+ 41 - 48
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexUtils.cs

@@ -10,15 +10,16 @@ namespace SharpGLTF.Geometry.VertexTypes
 
 
     public static class VertexUtils
     public static class VertexUtils
     {
     {
-        public static IEnumerable<MemoryAccessor[]> CreateVertexMemoryAccessors<TVertex, TJoints>(this IEnumerable<IReadOnlyList<(TVertex, TJoints)>> vertexBlocks)
-            where TVertex : struct, IVertex
-            where TJoints : struct, IJoints
+        public static IEnumerable<MemoryAccessor[]> CreateVertexMemoryAccessors<TvP, TvM, TvJ>(this IEnumerable<IReadOnlyList<(TvP, TvM, TvJ)>> vertexBlocks)
+            where TvP : struct, IVertexPosition
+            where TvM : struct, IVertexMaterial
+            where TvJ : struct, IVertexJoints
         {
         {
             // total number of vertices
             // total number of vertices
             var totalCount = vertexBlocks.Sum(item => item.Count);
             var totalCount = vertexBlocks.Sum(item => item.Count);
 
 
             // vertex attributes
             // vertex attributes
-            var attributes = GetVertexAttributes(typeof(TVertex), typeof(TJoints), totalCount);
+            var attributes = GetVertexAttributes(typeof(TvP), typeof(TvM), typeof(TvJ), totalCount);
 
 
             // create master vertex buffer
             // create master vertex buffer
             int byteStride = attributes[0].ByteStride;
             int byteStride = attributes[0].ByteStride;
@@ -35,18 +36,12 @@ namespace SharpGLTF.Geometry.VertexTypes
 
 
                 foreach (var accessor in accessors)
                 foreach (var accessor in accessors)
                 {
                 {
-                    bool isSkin = false;
-                    var finfo = GetVertexField(typeof(TVertex), accessor.Attribute.Name);
-                    if (finfo == null)
-                    {
-                        finfo = GetVertexField(typeof(TJoints), accessor.Attribute.Name);
-                        isSkin = true;
-                    }
-
-                    if (accessor.Attribute.Dimensions == Schema2.DimensionType.SCALAR) accessor.Fill(GetScalarColumn(finfo, block, isSkin));
-                    if (accessor.Attribute.Dimensions == Schema2.DimensionType.VEC2) accessor.Fill(GetVector2Column(finfo, block, isSkin));
-                    if (accessor.Attribute.Dimensions == Schema2.DimensionType.VEC3) accessor.Fill(GetVector3Column(finfo, block, isSkin));
-                    if (accessor.Attribute.Dimensions == Schema2.DimensionType.VEC4) accessor.Fill(GetVector4Column(finfo, block, isSkin));
+                    var columnFunc = GetItemValueFunc<TvP, TvM, TvJ>(accessor.Attribute.Name);
+
+                    if (accessor.Attribute.Dimensions == Schema2.DimensionType.SCALAR) accessor.Fill(block.GetScalarColumn(columnFunc));
+                    if (accessor.Attribute.Dimensions == Schema2.DimensionType.VEC2) accessor.Fill(block.GetVector2Column(columnFunc));
+                    if (accessor.Attribute.Dimensions == Schema2.DimensionType.VEC3) accessor.Fill(block.GetVector3Column(columnFunc));
+                    if (accessor.Attribute.Dimensions == Schema2.DimensionType.VEC4) accessor.Fill(block.GetVector4Column(columnFunc));
                 }
                 }
 
 
                 yield return accessors;
                 yield return accessors;
@@ -94,7 +89,7 @@ namespace SharpGLTF.Geometry.VertexTypes
             return null;
             return null;
         }
         }
 
 
-        private static MemoryAccessInfo[] GetVertexAttributes(Type vertexType, Type jointsType, int itemsCount)
+        private static MemoryAccessInfo[] GetVertexAttributes(Type vertexType, Type valuesType, Type jointsType, int itemsCount)
         {
         {
             var attributes = new List<MemoryAccessInfo>();
             var attributes = new List<MemoryAccessInfo>();
 
 
@@ -104,6 +99,12 @@ namespace SharpGLTF.Geometry.VertexTypes
                 if (attribute.HasValue) attributes.Add(attribute.Value);
                 if (attribute.HasValue) attributes.Add(attribute.Value);
             }
             }
 
 
+            foreach (var finfo in valuesType.GetFields())
+            {
+                var attribute = _GetMemoryAccessInfo(finfo);
+                if (attribute.HasValue) attributes.Add(attribute.Value);
+            }
+
             foreach (var finfo in jointsType.GetFields())
             foreach (var finfo in jointsType.GetFields())
             {
             {
                 var attribute = _GetMemoryAccessInfo(finfo);
                 var attribute = _GetMemoryAccessInfo(finfo);
@@ -139,57 +140,49 @@ 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);
         }
         }
 
 
-        internal static Single[] GetScalarColumn<TVertex, TJoints>(this System.Reflection.FieldInfo finfo, IReadOnlyList<(TVertex, TJoints)> vertices, bool vertexOrSkin)
+        private static Func<(TvP, TvM, TvJ), Object> GetItemValueFunc<TvP, TvM, TvJ>(string attributeName)
         {
         {
-            var dst = new Single[vertices.Count];
+            var finfo = GetVertexField(typeof(TvP), attributeName);
+            if (finfo != null) return vertex => finfo.GetValue(vertex.Item1);
 
 
-            for (int i = 0; i < dst.Length; ++i)
-            {
-                var v = vertices[i];
+            finfo = GetVertexField(typeof(TvM), attributeName);
+            if (finfo != null) return vertex => finfo.GetValue(vertex.Item2);
 
 
-                dst[i] = vertexOrSkin ? (Single)finfo.GetValue(v.Item2) : (Single)finfo.GetValue(v.Item1);
-            }
+            finfo = GetVertexField(typeof(TvJ), attributeName);
+            if (finfo != null) return vertex => finfo.GetValue(vertex.Item3);
 
 
-            return dst;
+            throw new NotImplementedException();
         }
         }
 
 
-        internal static Vector2[] GetVector2Column<TVertex, TJoints>(this System.Reflection.FieldInfo finfo, IReadOnlyList<(TVertex, TJoints)> vertices, bool vertexOrSkin)
+        internal static Single[] GetScalarColumn<TvP, TvM, TvJ>(this IReadOnlyList<(TvP, TvM, TvJ)> vertices, Func<(TvP, TvM, TvJ), Object> func)
         {
         {
-            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;
+            return GetColumn<TvP, TvM, TvJ, Single>(vertices, func);
         }
         }
 
 
-        internal static Vector3[] GetVector3Column<TVertex, TJoints>(this System.Reflection.FieldInfo finfo, IReadOnlyList<(TVertex, TJoints)> vertices, bool vertexOrSkin)
+        internal static Vector2[] GetVector2Column<TvP, TvM, TvJ>(this IReadOnlyList<(TvP, TvM, TvJ)> vertices, Func<(TvP, TvM, TvJ), Object> func)
         {
         {
-            var dst = new Vector3[vertices.Count];
-
-            for (int i = 0; i < dst.Length; ++i)
-            {
-                var v = vertices[i];
+            return GetColumn<TvP, TvM, TvJ, Vector2>(vertices, func);
+        }
 
 
-                dst[i] = vertexOrSkin ? (Vector3)finfo.GetValue(v.Item2) : (Vector3)finfo.GetValue(v.Item1);
-            }
+        internal static Vector3[] GetVector3Column<TvP, TvM, TvJ>(this IReadOnlyList<(TvP, TvM, TvJ)> vertices, Func<(TvP, TvM, TvJ), Object> func)
+        {
+            return GetColumn<TvP, TvM, TvJ, Vector3>(vertices, func);
+        }
 
 
-            return dst;
+        internal static Vector4[] GetVector4Column<TvP, TvM, TvJ>(this IReadOnlyList<(TvP, TvM, TvJ)> vertices, Func<(TvP, TvM, TvJ), Object> func)
+        {
+            return GetColumn<TvP, TvM, TvJ, Vector4>(vertices, func);
         }
         }
 
 
-        internal static Vector4[] GetVector4Column<TVertex, TJoints>(this System.Reflection.FieldInfo finfo, IReadOnlyList<(TVertex, TJoints)> vertices, bool vertexOrSkin)
+        internal static TColumn[] GetColumn<TvP, TvM, TvJ, TColumn>(this IReadOnlyList<(TvP, TvM, TvJ)> vertices, Func<(TvP, TvM, TvJ), Object> func)
         {
         {
-            var dst = new Vector4[vertices.Count];
+            var dst = new TColumn[vertices.Count];
 
 
             for (int i = 0; i < dst.Length; ++i)
             for (int i = 0; i < dst.Length; ++i)
             {
             {
                 var v = vertices[i];
                 var v = vertices[i];
 
 
-                dst[i] = vertexOrSkin ? (Vector4)finfo.GetValue(v.Item2) : (Vector4)finfo.GetValue(v.Item1);
+                dst[i] = (TColumn)func(v);
             }
             }
 
 
             return dst;
             return dst;

+ 32 - 18
src/SharpGLTF.Toolkit/Schema2/MeshExtensions.cs

@@ -12,30 +12,34 @@ namespace SharpGLTF.Schema2
     {
     {
         #region meshes
         #region meshes
 
 
-        public static Mesh CreateMesh<TVertex, TJoints>(this ModelRoot root, Geometry.SkinnedMeshBuilder<Material, TVertex, TJoints> meshBuilder)
-            where TVertex : struct, Geometry.VertexTypes.IVertex
-            where TJoints : struct, Geometry.VertexTypes.IJoints
+        public static Mesh CreateMesh<TvP, TvM, TvJ>(this ModelRoot root, Geometry.MeshBuilder<Material, TvP, TvM, TvJ> meshBuilder)
+            where TvP : struct, Geometry.VertexTypes.IVertexPosition
+            where TvM : struct, Geometry.VertexTypes.IVertexMaterial
+            where TvJ : struct, Geometry.VertexTypes.IVertexJoints
         {
         {
             return root.CreateMeshes(m => m, meshBuilder).First();
             return root.CreateMeshes(m => m, meshBuilder).First();
         }
         }
 
 
-        public static Mesh CreateMesh<TMaterial, TVertex, TJoints>(this ModelRoot root, Func<TMaterial, Material> materialEvaluator, Geometry.SkinnedMeshBuilder<TMaterial, TVertex, TJoints> meshBuilder)
-            where TVertex : struct, Geometry.VertexTypes.IVertex
-            where TJoints : struct, Geometry.VertexTypes.IJoints
+        public static Mesh CreateMesh<TMaterial, TvP, TvM, TvJ>(this ModelRoot root, Func<TMaterial, Material> materialEvaluator, Geometry.MeshBuilder<TMaterial, TvP, TvM, TvJ> meshBuilder)
+            where TvP : struct, Geometry.VertexTypes.IVertexPosition
+            where TvM : struct, Geometry.VertexTypes.IVertexMaterial
+            where TvJ : struct, Geometry.VertexTypes.IVertexJoints
         {
         {
             return root.CreateMeshes(materialEvaluator, meshBuilder).First();
             return root.CreateMeshes(materialEvaluator, meshBuilder).First();
         }
         }
 
 
-        public static IReadOnlyList<Mesh> CreateMeshes<TVertex, TJoints>(this ModelRoot root, params Geometry.SkinnedMeshBuilder<Material, TVertex, TJoints>[] meshBuilders)
-            where TVertex : struct, Geometry.VertexTypes.IVertex
-            where TJoints : struct, Geometry.VertexTypes.IJoints
+        public static IReadOnlyList<Mesh> CreateMeshes<TvP, TvM, TvJ>(this ModelRoot root, params Geometry.MeshBuilder<Material, TvP, TvM, TvJ>[] meshBuilders)
+            where TvP : struct, Geometry.VertexTypes.IVertexPosition
+            where TvM : struct, Geometry.VertexTypes.IVertexMaterial
+            where TvJ : struct, Geometry.VertexTypes.IVertexJoints
         {
         {
-            return root.CreateMeshes<Material, TVertex, TJoints>(k => k, meshBuilders);
+            return root.CreateMeshes(k => k, meshBuilders);
         }
         }
 
 
-        public static IReadOnlyList<Mesh> CreateMeshes<TMaterial, TVertex, TJoints>(this ModelRoot root, Func<TMaterial, Material> materialEvaluator, params Geometry.SkinnedMeshBuilder<TMaterial, TVertex, TJoints>[] meshBuilders)
-            where TVertex : struct, Geometry.VertexTypes.IVertex
-            where TJoints : struct, Geometry.VertexTypes.IJoints
+        public static IReadOnlyList<Mesh> CreateMeshes<TMaterial, TvP, TvM, TvJ>(this ModelRoot root, Func<TMaterial, Material> materialEvaluator, params Geometry.MeshBuilder<TMaterial, TvP, TvM, TvJ>[] meshBuilders)
+            where TvP : struct, Geometry.VertexTypes.IVertexPosition
+            where TvM : struct, Geometry.VertexTypes.IVertexMaterial
+            where TvJ : struct, Geometry.VertexTypes.IVertexJoints
         {
         {
             // create a new material for every unique material in the mesh builders.
             // create a new material for every unique material in the mesh builders.
             var mapMaterials = meshBuilders
             var mapMaterials = meshBuilders
@@ -165,16 +169,26 @@ namespace SharpGLTF.Schema2
         }
         }
 
 
         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, Geometry.VertexTypes.IVertex
+            where TVertex : struct, Geometry.VertexTypes.IVertexPosition
         {
         {
-            var xvertices = vertices.Select(item => (item, default(Geometry.VertexTypes.VertexJoints0))).ToList();
+            var xvertices = vertices.Select(item => (item, default(Geometry.VertexTypes.VertexEmpty), default(Geometry.VertexTypes.VertexEmpty))).ToList();
 
 
             return primitive.WithVertexAccessors(xvertices);
             return primitive.WithVertexAccessors(xvertices);
         }
         }
 
 
-        public static MeshPrimitive WithVertexAccessors<TVertex, TJoints>(this MeshPrimitive primitive, IReadOnlyList<(TVertex, TJoints)> vertices)
-            where TVertex : struct, Geometry.VertexTypes.IVertex
-            where TJoints : struct, Geometry.VertexTypes.IJoints
+        public static MeshPrimitive WithVertexAccessors<TVertex, TValues>(this MeshPrimitive primitive, IReadOnlyList<(TVertex, TValues)> vertices)
+            where TVertex : struct, Geometry.VertexTypes.IVertexPosition
+            where TValues : struct, Geometry.VertexTypes.IVertexMaterial
+        {
+            var xvertices = vertices.Select(item => (item.Item1, item.Item2, default(Geometry.VertexTypes.VertexEmpty))).ToList();
+
+            return primitive.WithVertexAccessors(xvertices);
+        }
+
+        public static MeshPrimitive WithVertexAccessors<TVertex, TValues, TJoints>(this MeshPrimitive primitive, IReadOnlyList<(TVertex, TValues, TJoints)> vertices)
+            where TVertex : struct, Geometry.VertexTypes.IVertexPosition
+            where TValues : struct, Geometry.VertexTypes.IVertexMaterial
+            where TJoints : struct, Geometry.VertexTypes.IVertexJoints
         {
         {
             var memAccessors = Geometry.VertexTypes.VertexUtils.CreateVertexMemoryAccessors(new[] { vertices }).First();
             var memAccessors = Geometry.VertexTypes.VertexUtils.CreateVertexMemoryAccessors(new[] { vertices }).First();
 
 

+ 1 - 0
src/SharpGLTF.Toolkit/SharpGLTF.Toolkit.csproj

@@ -53,6 +53,7 @@
 
 
   <ItemGroup>
   <ItemGroup>
     <Compile Include="..\Shared\Guard.cs" Link="Debug\Guard.cs" />
     <Compile Include="..\Shared\Guard.cs" Link="Debug\Guard.cs" />
+    <Compile Include="..\Shared\_Extensions.cs" Link="_Extensions.cs" />
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup>
   <ItemGroup>

+ 3 - 0
tests/SharpGLTF.Tests/ExtensionsTests.cs

@@ -4,8 +4,11 @@ using System.Text;
 
 
 using NUnit.Framework;
 using NUnit.Framework;
 
 
+
 namespace SharpGLTF
 namespace SharpGLTF
 {
 {
+    using Schema2;
+
     [TestFixture]
     [TestFixture]
     public class ExtensionsTests
     public class ExtensionsTests
     {
     {

+ 4 - 4
tests/SharpGLTF.Tests/Memory/MemoryArrayTests.cs

@@ -57,11 +57,11 @@ namespace SharpGLTF.Memory
 
 
             var bytes = new Byte[256];
             var bytes = new Byte[256];
 
 
-            var v4n = new Vector4Array(bytes.Slice(0), 0, Schema2.EncodingType.UNSIGNED_BYTE, true);
+            var v4n = new Vector4Array(bytes, 0, Schema2.EncodingType.UNSIGNED_BYTE, true);
             v4n[1] = v1;
             v4n[1] = v1;
             VectorAssert.AreEqual(v4n[1], v1, 0.1f);
             VectorAssert.AreEqual(v4n[1], v1, 0.1f);
 
 
-            var v4u = new Vector4Array(bytes.Slice(0), 0, Schema2.EncodingType.UNSIGNED_BYTE, false);
+            var v4u = new Vector4Array(bytes, 0, Schema2.EncodingType.UNSIGNED_BYTE, false);
             v4u[1] = v2;
             v4u[1] = v2;
             VectorAssert.AreEqual(v4u[1], v2);
             VectorAssert.AreEqual(v4u[1], v2);
         }
         }
@@ -74,8 +74,8 @@ namespace SharpGLTF.Memory
 
 
             var bytes = new Byte[256];
             var bytes = new Byte[256];
 
 
-            var v4n = new Vector4Array(bytes.Slice(0), 0, 5, 8, Schema2.EncodingType.UNSIGNED_BYTE, true);
-            var v4u = new Vector4Array(bytes.Slice(0), 4, 5, 8, Schema2.EncodingType.UNSIGNED_BYTE, false);
+            var v4n = new Vector4Array(bytes, 0, 5, 8, Schema2.EncodingType.UNSIGNED_BYTE, true);
+            var v4u = new Vector4Array(bytes, 4, 5, 8, Schema2.EncodingType.UNSIGNED_BYTE, false);
 
 
             v4n[1] = v1;
             v4n[1] = v1;
             VectorAssert.AreEqual(v4n[1], v1, 0.1f);
             VectorAssert.AreEqual(v4n[1], v1, 0.1f);

+ 19 - 15
tests/SharpGLTF.Tests/Schema2/Authoring/CreateModelTests.cs

@@ -10,6 +10,7 @@ namespace SharpGLTF.Schema2.Authoring
 {
 {
     using Geometry;
     using Geometry;
 
 
+    using VEMPTY = Geometry.VertexTypes.VertexEmpty;
     using STATICVERTEX = Geometry.VertexTypes.VertexPositionNormal;
     using STATICVERTEX = Geometry.VertexTypes.VertexPositionNormal;
     using VPOS = Geometry.VertexTypes.VertexPosition;
     using VPOS = Geometry.VertexTypes.VertexPosition;
     using SKIN4 = Geometry.VertexTypes.VertexJoints4;
     using SKIN4 = Geometry.VertexTypes.VertexJoints4;
@@ -244,7 +245,7 @@ namespace SharpGLTF.Schema2.Authoring
             TestContext.CurrentContext.AttachShowDirLink();
             TestContext.CurrentContext.AttachShowDirLink();
             TestContext.CurrentContext.AttachGltfValidatorLink();
             TestContext.CurrentContext.AttachGltfValidatorLink();
 
 
-            var meshBuilder = new StaticMeshBuilder<Vector4, STATICVERTEX>("mesh1");
+            var meshBuilder = new MeshBuilder<Vector4, STATICVERTEX>("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);
@@ -272,10 +273,10 @@ namespace SharpGLTF.Schema2.Authoring
             TestContext.CurrentContext.AttachGltfValidatorLink();
             TestContext.CurrentContext.AttachGltfValidatorLink();
 
 
             // create several meshes
             // create several meshes
-            var meshBuilder1 = new StaticMeshBuilder<Vector4, STATICVERTEX>("mesh1");
-            var meshBuilder2 = new StaticMeshBuilder<Vector4, STATICVERTEX>("mesh2");
-            var meshBuilder3 = new StaticMeshBuilder<Vector4, STATICVERTEX>("mesh3");
-            var meshBuilder4 = new StaticMeshBuilder<Vector4, STATICVERTEX>("mesh4");
+            var meshBuilder1 = new MeshBuilder<Vector4, STATICVERTEX>("mesh1");
+            var meshBuilder2 = new MeshBuilder<Vector4, STATICVERTEX>("mesh2");
+            var meshBuilder3 = new MeshBuilder<Vector4, STATICVERTEX>("mesh3");
+            var meshBuilder4 = new MeshBuilder<Vector4, STATICVERTEX>("mesh4");
 
 
             meshBuilder1.AddCube(new Vector4(1, 1, 0, 1), Matrix4x4.Identity);
             meshBuilder1.AddCube(new Vector4(1, 1, 0, 1), Matrix4x4.Identity);
             meshBuilder2.AddCube(new Vector4(1, 0, 1, 1), Matrix4x4.Identity);
             meshBuilder2.AddCube(new Vector4(1, 0, 1, 1), Matrix4x4.Identity);
@@ -323,7 +324,7 @@ namespace SharpGLTF.Schema2.Authoring
             };
             };
 
 
             // create a mesh
             // create a mesh
-            var meshBuilder = new StaticMeshBuilder<Vector4, STATICVERTEX>("mesh1");
+            var meshBuilder = new MeshBuilder<Vector4, STATICVERTEX>("mesh1");
             meshBuilder.AddCube(Vector4.One, Matrix4x4.Identity);            
             meshBuilder.AddCube(Vector4.One, Matrix4x4.Identity);            
 
 
             // create the gltf model
             // create the gltf model
@@ -354,7 +355,7 @@ namespace SharpGLTF.Schema2.Authoring
             };
             };
             
             
             // create the mesh
             // create the mesh
-            var meshBuilder = new SkinnedMeshBuilder<Vector4, VPOS, SKIN4>("mesh1");
+            var meshBuilder = new MeshBuilder<Vector4, VPOS, VEMPTY, SKIN4>("mesh1");
 
 
             var v1 = (new VPOS(-10, 0, +10), new SKIN4(0));
             var v1 = (new VPOS(-10, 0, +10), new SKIN4(0));
             var v2 = (new VPOS(+10, 0, +10), new SKIN4(0));
             var v2 = (new VPOS(+10, 0, +10), new SKIN4(0));
@@ -371,15 +372,18 @@ namespace SharpGLTF.Schema2.Authoring
             var v11 = (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));
             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), v2, v3, v7, v6);
-            meshBuilder.AddPolygon(new Vector4(1, 0, 1, 1), v3, v4, v8, v7);
-            meshBuilder.AddPolygon(new Vector4(1, 0, 1, 1), v4, v1, v5, v8);
+            var pink = new Vector4(1, 0, 1, 1);
+            var yellow = new Vector4(1, 1, 0, 1);
 
 
-            meshBuilder.AddPolygon(new Vector4(1, 1, 0, 1), v5, v6, v10, v9);
-            meshBuilder.AddPolygon(new Vector4(1, 1, 0, 1), v6, v7, v11, v10);
-            meshBuilder.AddPolygon(new Vector4(1, 1, 0, 1), v7, v8, v12, v11);
-            meshBuilder.AddPolygon(new Vector4(1, 1, 0, 1), v8, v5, v9, v12);
+            meshBuilder.AddPolygon(pink, v1, v2, v6, v5);
+            meshBuilder.AddPolygon(pink, v2, v3, v7, v6);
+            meshBuilder.AddPolygon(pink, v3, v4, v8, v7);
+            meshBuilder.AddPolygon(pink, v4, v1, v5, v8);
+
+            meshBuilder.AddPolygon(yellow, v5, v6, v10, v9);
+            meshBuilder.AddPolygon(yellow, v6, v7, v11, v10);
+            meshBuilder.AddPolygon(yellow, v7, v8, v12, v11);
+            meshBuilder.AddPolygon(yellow, v8, v5, v9, v12);
 
 
             // create base model
             // create base model
             var model = ModelRoot.CreateModel();
             var model = ModelRoot.CreateModel();

+ 5 - 6
tests/SharpGLTF.Tests/Schema2/Authoring/SolidMeshUtils.cs

@@ -5,14 +5,13 @@ using System.Text;
 
 
 namespace SharpGLTF.Schema2.Authoring
 namespace SharpGLTF.Schema2.Authoring
 {
 {
-    using Geometry;
+    using Geometry;    
     
     
     using VPOSNRM = Geometry.VertexTypes.VertexPositionNormal;
     using VPOSNRM = Geometry.VertexTypes.VertexPositionNormal;
-    
 
 
     static class SolidMeshUtils
     static class SolidMeshUtils
     {
     {
-        public static void AddCube<TMaterial>(this StaticMeshBuilder<TMaterial, VPOSNRM> meshBuilder, TMaterial material, Matrix4x4 xform)
+        public static void AddCube<TMaterial>(this MeshBuilder<TMaterial, VPOSNRM> meshBuilder, TMaterial material, Matrix4x4 xform)
         {
         {
             meshBuilder._AddCubeFace(material, Vector3.UnitX, Vector3.UnitY, Vector3.UnitZ, xform);
             meshBuilder._AddCubeFace(material, Vector3.UnitX, Vector3.UnitY, Vector3.UnitZ, xform);
             meshBuilder._AddCubeFace(material, -Vector3.UnitX, Vector3.UnitZ, Vector3.UnitY, xform);
             meshBuilder._AddCubeFace(material, -Vector3.UnitX, Vector3.UnitZ, Vector3.UnitY, xform);
@@ -24,7 +23,7 @@ namespace SharpGLTF.Schema2.Authoring
             meshBuilder._AddCubeFace(material, -Vector3.UnitZ, Vector3.UnitY, Vector3.UnitX, xform);
             meshBuilder._AddCubeFace(material, -Vector3.UnitZ, Vector3.UnitY, Vector3.UnitX, xform);
         }
         }
 
 
-        private static void _AddCubeFace<TMaterial>(this StaticMeshBuilder<TMaterial, VPOSNRM> meshBuilder, TMaterial material, Vector3 origin, Vector3 axisX, Vector3 axisY, Matrix4x4 xform)
+        private static void _AddCubeFace<TMaterial>(this MeshBuilder<TMaterial, VPOSNRM> meshBuilder, TMaterial material, Vector3 origin, Vector3 axisX, Vector3 axisY, Matrix4x4 xform)
         {
         {
             var p1 = Vector3.Transform(origin - axisX - axisY, xform);
             var p1 = Vector3.Transform(origin - axisX - axisY, xform);
             var p2 = Vector3.Transform(origin + axisX - axisY, xform);
             var p2 = Vector3.Transform(origin + axisX - axisY, xform);
@@ -41,7 +40,7 @@ namespace SharpGLTF.Schema2.Authoring
                 );
                 );
         }
         }
 
 
-        public static void AddSphere<TMaterial>(this StaticMeshBuilder<TMaterial, VPOSNRM> meshBuilder, TMaterial material, Single radius, Matrix4x4 xform)
+        public static void AddSphere<TMaterial>(this MeshBuilder<TMaterial, VPOSNRM> meshBuilder, TMaterial material, Single radius, Matrix4x4 xform)
         {
         {
             // http://blog.andreaskahler.com/2009/06/creating-icosphere-mesh-in-code.html
             // http://blog.andreaskahler.com/2009/06/creating-icosphere-mesh-in-code.html
 
 
@@ -91,7 +90,7 @@ namespace SharpGLTF.Schema2.Authoring
             meshBuilder._AddSphereTriangle(material, xform, v9, v8, v1, 3);
             meshBuilder._AddSphereTriangle(material, xform, v9, v8, v1, 3);
         }
         }
 
 
-        private static void _AddSphereTriangle<TMaterial>(this StaticMeshBuilder<TMaterial, VPOSNRM> meshBuilder, TMaterial material, Matrix4x4 xform, Vector3 a, Vector3 b, Vector3 c, int iterations = 0)
+        private static void _AddSphereTriangle<TMaterial>(this MeshBuilder<TMaterial, VPOSNRM> meshBuilder, TMaterial material, Matrix4x4 xform, Vector3 a, Vector3 b, Vector3 c, int iterations = 0)
         {
         {
             if (iterations <=0)
             if (iterations <=0)
             {
             {

+ 6 - 5
tests/SharpGLTF.Tests/WavefrontWriter.cs

@@ -8,7 +8,8 @@ using static System.FormattableString;
 
 
 namespace SharpGLTF
 namespace SharpGLTF
 {
 {
-    using VERTEX = Geometry.VertexTypes.VertexPositionNormal;
+    using POSITION = Geometry.VertexTypes.VertexPositionNormal;
+    using TEXCOORD = Geometry.VertexTypes.VertexEmpty;
     using MATERIAL = Vector4;
     using MATERIAL = Vector4;
 
 
     /// <summary>
     /// <summary>
@@ -18,7 +19,7 @@ namespace SharpGLTF
     {
     {
         #region data
         #region data
 
 
-        private readonly Geometry.StaticMeshBuilder<MATERIAL, VERTEX> _Mesh = new Geometry.StaticMeshBuilder<MATERIAL, VERTEX>();
+        private readonly Geometry.MeshBuilder<MATERIAL, POSITION, TEXCOORD> _Mesh = new Geometry.MeshBuilder<MATERIAL, POSITION, TEXCOORD>();
         
         
         #endregion
         #endregion
 
 
@@ -26,9 +27,9 @@ namespace SharpGLTF
 
 
         public void AddTriangle(Vector3 a, Vector3 b, Vector3 c)
         public void AddTriangle(Vector3 a, Vector3 b, Vector3 c)
         {
         {
-            var aa = new VERTEX { Position = a };
-            var bb = new VERTEX { Position = b };
-            var cc = new VERTEX { Position = c };
+            var aa = new POSITION { Position = a };
+            var bb = new POSITION { Position = b };
+            var cc = new POSITION { Position = c };
 
 
             _Mesh.AddTriangle(Vector4.One, aa, bb, cc);
             _Mesh.AddTriangle(Vector4.One, aa, bb, cc);
         }
         }