Browse Source

Vertex attribute definitions are not AOT friendly, so now there's a IVertexReflection interface that serves the same purpose and it is AOT friendly.

vpenades 1 year ago
parent
commit
e2e2bbe6d8

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

@@ -26,6 +26,11 @@ namespace SharpGLTF.Geometry.VertexTypes
 
         #region data
 
+        IEnumerable<KeyValuePair<string, Memory.AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield break;
+        }
+
         public override int GetHashCode() { return 0; }
         public override bool Equals(object obj) { return obj is VertexEmpty; }
         public bool Equals(VertexEmpty other) { return true; }

+ 29 - 2
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexGeometry.cs

@@ -5,6 +5,8 @@ using System.Numerics;
 using System.Runtime.Serialization;
 using System.Text;
 
+using SharpGLTF.Memory;
+
 namespace SharpGLTF.Geometry.VertexTypes
 {
     /// <summary>
@@ -19,7 +21,7 @@ namespace SharpGLTF.Geometry.VertexTypes
     /// <item><see cref="VertexGeometryDelta"/></item>
     /// </list>
     /// </remarks>
-    public interface IVertexGeometry
+    public interface IVertexGeometry : IVertexReflection
     {
         /// <summary>
         /// Gets the position of the vertex.
@@ -129,6 +131,11 @@ namespace SharpGLTF.Geometry.VertexTypes
         [VertexAttribute("POSITION")]
         public Vector3 Position;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>("POSITION", new AttributeFormat(Schema2.DimensionType.VEC3));
+        }
+
         /// <inheritdoc/>
         public readonly override int GetHashCode() { return Position.GetHashCode(); }
 
@@ -179,7 +186,7 @@ namespace SharpGLTF.Geometry.VertexTypes
         public void ApplyTransform(in Matrix4x4 xform)
         {
             Position = Vector3.Transform(Position, xform);
-        }
+        }        
 
         #endregion
     }
@@ -236,6 +243,12 @@ namespace SharpGLTF.Geometry.VertexTypes
         [VertexAttribute("NORMAL")]
         public Vector3 Normal;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>("POSITION", new AttributeFormat(Schema2.DimensionType.VEC3));
+            yield return new KeyValuePair<string, AttributeFormat>("NORMAL", new AttributeFormat(Schema2.DimensionType.VEC3));
+        }
+
         /// <inheritdoc/>
         public readonly override int GetHashCode() { return Position.GetHashCode(); }
 
@@ -344,6 +357,13 @@ namespace SharpGLTF.Geometry.VertexTypes
         [VertexAttribute("TANGENT")]
         public Vector4 Tangent;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>("POSITION", new AttributeFormat(Schema2.DimensionType.VEC3));
+            yield return new KeyValuePair<string, AttributeFormat>("NORMAL", new AttributeFormat(Schema2.DimensionType.VEC3));
+            yield return new KeyValuePair<string, AttributeFormat>("TANGENT", new AttributeFormat(Schema2.DimensionType.VEC4));
+        }
+
         /// <inheritdoc/>
         public readonly override int GetHashCode() { return Position.GetHashCode(); }
 
@@ -499,6 +519,13 @@ namespace SharpGLTF.Geometry.VertexTypes
         [VertexAttribute("TANGENTDELTA")]
         public Vector3 TangentDelta;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>("POSITIONDELTA", new AttributeFormat(Schema2.DimensionType.VEC3));
+            yield return new KeyValuePair<string, AttributeFormat>("NORMALDELTA", new AttributeFormat(Schema2.DimensionType.VEC3));
+            yield return new KeyValuePair<string, AttributeFormat>("TANGENTDELTA", new AttributeFormat(Schema2.DimensionType.VEC3));
+        }
+
         /// <inheritdoc/>
         public readonly override int GetHashCode() { return PositionDelta.GetHashCode(); }
 

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

@@ -13,6 +13,7 @@ using System.Diagnostics.CodeAnalysis;
 using System.Numerics;
 using System.Text;
 
+using SharpGLTF.Memory;
 
 using ENCODING = SharpGLTF.Schema2.EncodingType;
 
@@ -55,6 +56,10 @@ namespace SharpGLTF.Geometry.VertexTypes
          [VertexAttribute("TEXCOORD_0")]
          public Vector2 TexCoord;
 
+         IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+         {
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_0", new AttributeFormat(Schema2.DimensionType.VEC2));
+         }
          public readonly int MaxColors => 0;
 
          public readonly int MaxTextCoords => 1;
@@ -160,6 +165,11 @@ namespace SharpGLTF.Geometry.VertexTypes
          [VertexAttribute("TEXCOORD_1")]
          public Vector2 TexCoord1;
 
+         IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+         {
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_0", new AttributeFormat(Schema2.DimensionType.VEC2));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_1", new AttributeFormat(Schema2.DimensionType.VEC2));
+         }
          public readonly int MaxColors => 0;
 
          public readonly int MaxTextCoords => 2;
@@ -274,6 +284,12 @@ namespace SharpGLTF.Geometry.VertexTypes
          [VertexAttribute("TEXCOORD_2")]
          public Vector2 TexCoord2;
 
+         IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+         {
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_0", new AttributeFormat(Schema2.DimensionType.VEC2));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_1", new AttributeFormat(Schema2.DimensionType.VEC2));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_2", new AttributeFormat(Schema2.DimensionType.VEC2));
+         }
          public readonly int MaxColors => 0;
 
          public readonly int MaxTextCoords => 3;
@@ -396,6 +412,13 @@ namespace SharpGLTF.Geometry.VertexTypes
          [VertexAttribute("TEXCOORD_3")]
          public Vector2 TexCoord3;
 
+         IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+         {
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_0", new AttributeFormat(Schema2.DimensionType.VEC2));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_1", new AttributeFormat(Schema2.DimensionType.VEC2));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_2", new AttributeFormat(Schema2.DimensionType.VEC2));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_3", new AttributeFormat(Schema2.DimensionType.VEC2));
+         }
          public readonly int MaxColors => 0;
 
          public readonly int MaxTextCoords => 4;
@@ -507,6 +530,10 @@ namespace SharpGLTF.Geometry.VertexTypes
          [VertexAttribute("COLOR_0", ENCODING.UNSIGNED_BYTE, true)]
          public Vector4 Color;
 
+         IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+         {
+             yield return new KeyValuePair<string, AttributeFormat>("COLOR_0", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));
+         }
          public readonly int MaxColors => 1;
 
          public readonly int MaxTextCoords => 0;
@@ -612,6 +639,11 @@ namespace SharpGLTF.Geometry.VertexTypes
          [VertexAttribute("TEXCOORD_0")]
          public Vector2 TexCoord;
 
+         IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+         {
+             yield return new KeyValuePair<string, AttributeFormat>("COLOR_0", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_0", new AttributeFormat(Schema2.DimensionType.VEC2));
+         }
          public readonly int MaxColors => 1;
 
          public readonly int MaxTextCoords => 1;
@@ -726,6 +758,12 @@ namespace SharpGLTF.Geometry.VertexTypes
          [VertexAttribute("TEXCOORD_1")]
          public Vector2 TexCoord1;
 
+         IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+         {
+             yield return new KeyValuePair<string, AttributeFormat>("COLOR_0", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_0", new AttributeFormat(Schema2.DimensionType.VEC2));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_1", new AttributeFormat(Schema2.DimensionType.VEC2));
+         }
          public readonly int MaxColors => 1;
 
          public readonly int MaxTextCoords => 2;
@@ -849,6 +887,13 @@ namespace SharpGLTF.Geometry.VertexTypes
          [VertexAttribute("TEXCOORD_2")]
          public Vector2 TexCoord2;
 
+         IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+         {
+             yield return new KeyValuePair<string, AttributeFormat>("COLOR_0", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_0", new AttributeFormat(Schema2.DimensionType.VEC2));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_1", new AttributeFormat(Schema2.DimensionType.VEC2));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_2", new AttributeFormat(Schema2.DimensionType.VEC2));
+         }
          public readonly int MaxColors => 1;
 
          public readonly int MaxTextCoords => 3;
@@ -980,6 +1025,14 @@ namespace SharpGLTF.Geometry.VertexTypes
          [VertexAttribute("TEXCOORD_3")]
          public Vector2 TexCoord3;
 
+         IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+         {
+             yield return new KeyValuePair<string, AttributeFormat>("COLOR_0", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_0", new AttributeFormat(Schema2.DimensionType.VEC2));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_1", new AttributeFormat(Schema2.DimensionType.VEC2));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_2", new AttributeFormat(Schema2.DimensionType.VEC2));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_3", new AttributeFormat(Schema2.DimensionType.VEC2));
+         }
          public readonly int MaxColors => 1;
 
          public readonly int MaxTextCoords => 4;
@@ -1100,6 +1153,11 @@ namespace SharpGLTF.Geometry.VertexTypes
          [VertexAttribute("COLOR_1", ENCODING.UNSIGNED_BYTE, true)]
          public Vector4 Color1;
 
+         IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+         {
+             yield return new KeyValuePair<string, AttributeFormat>("COLOR_0", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));
+             yield return new KeyValuePair<string, AttributeFormat>("COLOR_1", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));
+         }
          public readonly int MaxColors => 2;
 
          public readonly int MaxTextCoords => 0;
@@ -1214,6 +1272,12 @@ namespace SharpGLTF.Geometry.VertexTypes
          [VertexAttribute("TEXCOORD_0")]
          public Vector2 TexCoord;
 
+         IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+         {
+             yield return new KeyValuePair<string, AttributeFormat>("COLOR_0", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));
+             yield return new KeyValuePair<string, AttributeFormat>("COLOR_1", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_0", new AttributeFormat(Schema2.DimensionType.VEC2));
+         }
          public readonly int MaxColors => 2;
 
          public readonly int MaxTextCoords => 1;
@@ -1337,6 +1401,13 @@ namespace SharpGLTF.Geometry.VertexTypes
          [VertexAttribute("TEXCOORD_1")]
          public Vector2 TexCoord1;
 
+         IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+         {
+             yield return new KeyValuePair<string, AttributeFormat>("COLOR_0", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));
+             yield return new KeyValuePair<string, AttributeFormat>("COLOR_1", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_0", new AttributeFormat(Schema2.DimensionType.VEC2));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_1", new AttributeFormat(Schema2.DimensionType.VEC2));
+         }
          public readonly int MaxColors => 2;
 
          public readonly int MaxTextCoords => 2;
@@ -1469,6 +1540,14 @@ namespace SharpGLTF.Geometry.VertexTypes
          [VertexAttribute("TEXCOORD_2")]
          public Vector2 TexCoord2;
 
+         IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+         {
+             yield return new KeyValuePair<string, AttributeFormat>("COLOR_0", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));
+             yield return new KeyValuePair<string, AttributeFormat>("COLOR_1", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_0", new AttributeFormat(Schema2.DimensionType.VEC2));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_1", new AttributeFormat(Schema2.DimensionType.VEC2));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_2", new AttributeFormat(Schema2.DimensionType.VEC2));
+         }
          public readonly int MaxColors => 2;
 
          public readonly int MaxTextCoords => 3;
@@ -1609,6 +1688,15 @@ namespace SharpGLTF.Geometry.VertexTypes
          [VertexAttribute("TEXCOORD_3")]
          public Vector2 TexCoord3;
 
+         IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+         {
+             yield return new KeyValuePair<string, AttributeFormat>("COLOR_0", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));
+             yield return new KeyValuePair<string, AttributeFormat>("COLOR_1", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_0", new AttributeFormat(Schema2.DimensionType.VEC2));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_1", new AttributeFormat(Schema2.DimensionType.VEC2));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_2", new AttributeFormat(Schema2.DimensionType.VEC2));
+             yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_3", new AttributeFormat(Schema2.DimensionType.VEC2));
+         }
          public readonly int MaxColors => 2;
 
          public readonly int MaxTextCoords => 4;

+ 10 - 3
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexMaterial.Permutations.tt

@@ -19,6 +19,7 @@ using System.Diagnostics.CodeAnalysis;
 using System.Numerics;
 using System.Text;
 
+using SharpGLTF.Memory;
 
 using ENCODING = SharpGLTF.Schema2.EncodingType;
 
@@ -74,14 +75,14 @@ void WriteVertexMaterialPermutation(int colorCount, int textureCount)
 
     WriteLine($"public {vertexTypeName}({attributeArgs})");      
     WriteLine("{"); PushIndent("    ");
-    foreach(var item in currentSet) { WriteLine($"{item.Param} = {item.Arg};"); }
+    foreach (var item in currentSet) { WriteLine($"{item.Param} = {item.Arg};"); }
     PopIndent(); WriteLine("}");    
 
     WriteLine($"public {vertexTypeName}(IVertexMaterial src)");   
     WriteLine("{"); PushIndent("    ");
     WriteLine("Guard.NotNull(src, nameof(src));");
-    for(int i=0; i < colorCount; ++i)   { WriteLine($"this.{colorsSet[i]} = {i} < src.MaxColors  ? src.GetColor({i}) : Vector4.One;"); }
-    for(int i=0; i < textureCount; ++i) { WriteLine($"this.{texcrdSet[i]} = {i} < src.MaxTextCoords ? src.GetTexCoord({i}) : Vector2.Zero;"); }
+    for (int i=0; i < colorCount; ++i)   { WriteLine($"this.{colorsSet[i]} = {i} < src.MaxColors  ? src.GetColor({i}) : Vector4.One;"); }
+    for (int i=0; i < textureCount; ++i) { WriteLine($"this.{texcrdSet[i]} = {i} < src.MaxTextCoords ? src.GetTexCoord({i}) : Vector2.Zero;"); }
     PopIndent(); WriteLine("}");
 
     WriteLine("#endregion"); WriteLine("");
@@ -104,6 +105,12 @@ void WriteVertexMaterialPermutation(int colorCount, int textureCount)
         WriteLine("");
     }
 
+    WriteLine("IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetAttributes()");
+    WriteLine("{"); PushIndent("    ");
+    for (int i=0; i < colorCount; ++i)   { var name = "COLOR_" + i; WriteLine($"yield return new KeyValuePair<string, AttributeFormat>(\"{name}\", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));"); }
+    for (int i=0; i < textureCount; ++i) { var name = "TEXCOORD_" + i; WriteLine($"yield return new KeyValuePair<string, AttributeFormat>(\"{name}\", new AttributeFormat(Schema2.DimensionType.VEC2));"); }
+    PopIndent(); WriteLine("}");
+
     WriteLine($"public readonly int MaxColors => {colorCount};");
     WriteLine("");
 

+ 14 - 3
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexMaterial.cs

@@ -4,6 +4,8 @@ using System.Diagnostics.CodeAnalysis;
 using System.Numerics;
 using System.Text;
 
+using SharpGLTF.Memory;
+
 using ENCODING = SharpGLTF.Schema2.EncodingType;
 
 namespace SharpGLTF.Geometry.VertexTypes
@@ -26,7 +28,7 @@ namespace SharpGLTF.Geometry.VertexTypes
     /// <item>And also by other custom vertex material fragment types.</item>
     /// </list>
     /// </remarks>
-    public interface IVertexMaterial
+    public interface IVertexMaterial : IVertexReflection
     {
         /// <summary>
         /// Gets the number of color attributes available in this vertex
@@ -181,8 +183,8 @@ namespace SharpGLTF.Geometry.VertexTypes
         {
             Guard.NotNull(src, nameof(src));
 
-            MaxColors = src.MaxColors;
-            MaxTextCoords = src.MaxTextCoords;
+            MaxColors = Math.Min(2, src.MaxColors);
+            MaxTextCoords = Math.Min(2,src.MaxTextCoords);
 
             if (src.MaxColors == 0)
             {
@@ -260,6 +262,15 @@ namespace SharpGLTF.Geometry.VertexTypes
         [VertexAttribute("TEXCOORD_1DELTA")]
         public Vector2 TexCoord1Delta;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>("COLOR_0DELTA", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));
+            yield return new KeyValuePair<string, AttributeFormat>("COLOR_1DELTA", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_BYTE, true));
+
+            yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_0DELTA", new AttributeFormat(Schema2.DimensionType.VEC2));
+            yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_1DELTA", new AttributeFormat(Schema2.DimensionType.VEC2));            
+        }
+
         /// <inheritdoc/>
         public int MaxColors { get; }
 

+ 15 - 0
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexReflection.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace SharpGLTF.Geometry.VertexTypes
+{
+    public interface IVertexReflection
+    {
+        /// <summary>
+        /// Gets the information used used to know how to encode the attributes stored in this vertex fragment.
+        /// </summary>
+        /// <returns>A list of attribute-encoding pairs</returns>
+        public IEnumerable<KeyValuePair<string, Memory.AttributeFormat>> GetEncodingAttributes();
+    }
+}

+ 17 - 1
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexSkinning.cs

@@ -3,6 +3,8 @@ using System.Collections.Generic;
 using System.Diagnostics.CodeAnalysis;
 using System.Numerics;
 using System.Text;
+
+using SharpGLTF.Memory;
 using SharpGLTF.Transforms;
 
 using ENCODING = SharpGLTF.Schema2.EncodingType;
@@ -20,7 +22,7 @@ namespace SharpGLTF.Geometry.VertexTypes
     /// <item><see cref="VertexJoints8"/></item>
     /// </list>
     /// </remarks>
-    public interface IVertexSkinning
+    public interface IVertexSkinning : IVertexReflection
     {
         /// <summary>
         /// Gets the Number of valid joints supported.<br/>Typical values are 0, 4 or 8.
@@ -142,6 +144,12 @@ namespace SharpGLTF.Geometry.VertexTypes
         [VertexAttribute("WEIGHTS_0")]
         public Vector4 Weights;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>("JOINTS_0", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_SHORT, false));
+            yield return new KeyValuePair<string, AttributeFormat>("WEIGHTS_0", new AttributeFormat(Schema2.DimensionType.VEC4));
+        }
+
         /// <inheritdoc/>
         public readonly int MaxBindings => 4;
 
@@ -301,6 +309,14 @@ namespace SharpGLTF.Geometry.VertexTypes
         [VertexAttribute("WEIGHTS_1")]
         public Vector4 Weights1;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>("JOINTS_0", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_SHORT, false));
+            yield return new KeyValuePair<string, AttributeFormat>("JOINTS_1", new AttributeFormat(Schema2.DimensionType.VEC4, ENCODING.UNSIGNED_SHORT, false));
+            yield return new KeyValuePair<string, AttributeFormat>("WEIGHTS_0", new AttributeFormat(Schema2.DimensionType.VEC4));
+            yield return new KeyValuePair<string, AttributeFormat>("WEIGHTS_1", new AttributeFormat(Schema2.DimensionType.VEC4));
+        }
+
         /// <inheritdoc/>
         public readonly int MaxBindings => 8;
 

+ 119 - 59
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexUtils.Accessors.cs

@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Numerics;
+using System.Runtime.CompilerServices;
 
 using SharpGLTF.Memory;
 
@@ -100,86 +101,59 @@ namespace SharpGLTF.Geometry.VertexTypes
 
         public static MemoryAccessInfo[] GetVertexAttributes(this IVertexBuilder firstVertex, int vertexCount, PackedEncoding vertexEncoding)
         {
-            var tvg = firstVertex.GetGeometry().GetType();
-            var tvm = firstVertex.GetMaterial().GetType();
-            var tvs = firstVertex.GetSkinning().GetType();
+            var tvg = firstVertex.GetGeometry().GetEncodingAttributes();
+            var tvm = firstVertex.GetMaterial().GetEncodingAttributes();
+            var tvs = firstVertex.GetSkinning().GetEncodingAttributes();
 
-            Guard.HasDynamicallyAccessedMembers(tvg, false, false, false, true, nameof(firstVertex));
-            Guard.HasDynamicallyAccessedMembers(tvm, false, false, false, true, nameof(firstVertex));
-            Guard.HasDynamicallyAccessedMembers(tvs, false, false, false, true, nameof(firstVertex));
-
-            var attributes = new List<MemoryAccessInfo>();
+            var attributes = new List<MemoryAccessInfo>();            
 
-            foreach (var finfo in tvg.GetFields())
-            {
-                var attribute = _GetMemoryAccessInfo(finfo);
-                if (attribute.HasValue) attributes.Add(attribute.Value);
+            foreach (var finfo in tvg)
+            {                
+                attributes.Add(new MemoryAccessInfo(finfo.Key, 0, 0, 0, finfo.Value));
             }
 
-            foreach (var finfo in tvm.GetFields())
+            foreach (var finfo in tvm)
             {
-                var attribute = _GetMemoryAccessInfo(finfo);
-                if (attribute.HasValue)
+                var a = new MemoryAccessInfo(finfo.Key, 0, 0, 0, finfo.Value);
+                
+                if (a.Name.StartsWith("COLOR_", StringComparison.OrdinalIgnoreCase))
                 {
-                    var a = attribute.Value;
-                    if (a.Name.StartsWith("COLOR_", StringComparison.OrdinalIgnoreCase))
+                    if (vertexEncoding.ColorEncoding.HasValue)
                     {
-                        if (vertexEncoding.ColorEncoding.HasValue)
-                        {
-                            a.Encoding = vertexEncoding.ColorEncoding.Value;
-                            a.Normalized = a.Encoding != ENCODING.FLOAT;
-                        }
+                        a.Encoding = vertexEncoding.ColorEncoding.Value;
+                        a.Normalized = a.Encoding != ENCODING.FLOAT;
                     }
-
-                    attributes.Add(a);
                 }
+
+                attributes.Add(a);
             }
 
-            foreach (var finfo in tvs.GetFields())
+            foreach (var finfo in tvs)
             {
-                var attribute = _GetMemoryAccessInfo(finfo);
-                if (attribute.HasValue)
+                var a = new MemoryAccessInfo(finfo.Key, 0, 0, 0, finfo.Value);                
+                
+                if (a.Name.StartsWith("JOINTS_", StringComparison.OrdinalIgnoreCase)) a.Encoding = vertexEncoding.JointsEncoding.Value;
+                if (a.Name.StartsWith("WEIGHTS_", StringComparison.OrdinalIgnoreCase))
                 {
-                    var a = attribute.Value;
-                    if (a.Name.StartsWith("JOINTS_", StringComparison.OrdinalIgnoreCase)) a.Encoding = vertexEncoding.JointsEncoding.Value;
-                    if (a.Name.StartsWith("WEIGHTS_", StringComparison.OrdinalIgnoreCase))
-                    {
-                        a.Encoding = vertexEncoding.WeightsEncoding.Value;
-                        if (a.Encoding != ENCODING.FLOAT) a.Normalized = true;
-                    }
-
-                    attributes.Add(a);
+                    a.Encoding = vertexEncoding.WeightsEncoding.Value;
+                    if (a.Encoding != ENCODING.FLOAT) a.Normalized = true;
                 }
+
+                attributes.Add(a);
+                
             }
 
             var array = attributes.ToArray();
 
             MemoryAccessInfo.SetInterleavedInfo(array, 0, vertexCount);
 
-            return array;
-        }
-
-        private static MemoryAccessInfo? _GetMemoryAccessInfo(System.Reflection.FieldInfo finfo)
-        {
-            var attribute = finfo.GetCustomAttributes(true)
-                    .OfType<VertexAttributeAttribute>()
-                    .FirstOrDefault();
-
-            if (attribute == null) return null;
-
-            var dimensions = (DIMENSIONS?)null;
-
-            if (finfo.FieldType == typeof(Single)) dimensions = DIMENSIONS.SCALAR;
-            if (finfo.FieldType == typeof(Vector2)) dimensions = DIMENSIONS.VEC2;
-            if (finfo.FieldType == typeof(Vector3)) dimensions = DIMENSIONS.VEC3;
-            if (finfo.FieldType == typeof(Vector4)) dimensions = DIMENSIONS.VEC4;
-            if (finfo.FieldType == typeof(Quaternion)) dimensions = DIMENSIONS.VEC4;
-            if (finfo.FieldType == typeof(Matrix4x4)) dimensions = DIMENSIONS.MAT4;
-
-            if (dimensions == null) throw new ArgumentException($"invalid type {finfo.FieldType}");
+            /*
+            var legacyArray = _GetVertexAttributesLegacy(firstVertex, vertexCount, vertexEncoding);
+            if (!array.SequenceEqual(legacyArray)) throw new InvalidOperationException();
+            */
 
-            return new MemoryAccessInfo(attribute.Name, 0, 0, 0, dimensions.Value, attribute.Encoding, attribute.Normalized);
-        }
+            return array;
+        }        
 
         private static Converter<IVertexBuilder, Object> _GetVertexBuilderAttributeFunc(string attributeName)
         {
@@ -240,5 +214,91 @@ namespace SharpGLTF.Geometry.VertexTypes
 
             return dst;
         }
+
+        // legacy
+
+        /*
+        private static MemoryAccessInfo[] _GetVertexAttributesLegacy(this IVertexBuilder firstVertex, int vertexCount, PackedEncoding vertexEncoding)
+        {
+            var tvg = firstVertex.GetGeometry().GetType();
+            var tvm = firstVertex.GetMaterial().GetType();
+            var tvs = firstVertex.GetSkinning().GetType();
+
+            Guard.HasDynamicallyAccessedMembers(tvg, false, false, false, true, nameof(firstVertex));
+            Guard.HasDynamicallyAccessedMembers(tvm, false, false, false, true, nameof(firstVertex));
+            Guard.HasDynamicallyAccessedMembers(tvs, false, false, false, true, nameof(firstVertex));
+
+            var attributes = new List<MemoryAccessInfo>();
+
+            foreach (var finfo in tvg.GetFields())
+            {
+                var attribute = _GetMemoryAccessInfo(finfo);
+                if (attribute.HasValue) attributes.Add(attribute.Value);
+            }
+
+            foreach (var finfo in tvm.GetFields())
+            {
+                var attribute = _GetMemoryAccessInfo(finfo);
+                if (attribute.HasValue)
+                {
+                    var a = attribute.Value;
+                    if (a.Name.StartsWith("COLOR_", StringComparison.OrdinalIgnoreCase))
+                    {
+                        if (vertexEncoding.ColorEncoding.HasValue)
+                        {
+                            a.Encoding = vertexEncoding.ColorEncoding.Value;
+                            a.Normalized = a.Encoding != ENCODING.FLOAT;
+                        }
+                    }
+
+                    attributes.Add(a);
+                }
+            }
+
+            foreach (var finfo in tvs.GetFields())
+            {
+                var attribute = _GetMemoryAccessInfo(finfo);
+                if (attribute.HasValue)
+                {
+                    var a = attribute.Value;
+                    if (a.Name.StartsWith("JOINTS_", StringComparison.OrdinalIgnoreCase)) a.Encoding = vertexEncoding.JointsEncoding.Value;
+                    if (a.Name.StartsWith("WEIGHTS_", StringComparison.OrdinalIgnoreCase))
+                    {
+                        a.Encoding = vertexEncoding.WeightsEncoding.Value;
+                        if (a.Encoding != ENCODING.FLOAT) a.Normalized = true;
+                    }
+
+                    attributes.Add(a);
+                }
+            }
+
+            var array = attributes.ToArray();
+
+            MemoryAccessInfo.SetInterleavedInfo(array, 0, vertexCount);
+
+            return array;
+        }
+
+        private static MemoryAccessInfo? _GetMemoryAccessInfo(System.Reflection.FieldInfo finfo)
+        {
+            var attribute = finfo.GetCustomAttributes(true)
+                    .OfType<VertexAttributeAttribute>()
+                    .FirstOrDefault();
+
+            if (attribute == null) return null;
+
+            var dimensions = (DIMENSIONS?)null;
+
+            if (finfo.FieldType == typeof(Single)) dimensions = DIMENSIONS.SCALAR;
+            if (finfo.FieldType == typeof(Vector2)) dimensions = DIMENSIONS.VEC2;
+            if (finfo.FieldType == typeof(Vector3)) dimensions = DIMENSIONS.VEC3;
+            if (finfo.FieldType == typeof(Vector4)) dimensions = DIMENSIONS.VEC4;
+            if (finfo.FieldType == typeof(Quaternion)) dimensions = DIMENSIONS.VEC4;
+            if (finfo.FieldType == typeof(Matrix4x4)) dimensions = DIMENSIONS.MAT4;
+
+            if (dimensions == null) throw new ArgumentException($"invalid type {finfo.FieldType}");
+
+            return new MemoryAccessInfo(attribute.Name, 0, 0, 0, dimensions.Value, attribute.Encoding, attribute.Normalized);
+        }*/
     }
 }

+ 8 - 0
tests/SharpGLTF.Cesium.Tests/VertexPointcloud.cs

@@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis;
 using System.Numerics;
 
 using SharpGLTF.Geometry.VertexTypes;
+using SharpGLTF.Memory;
 using SharpGLTF.Schema2;
 
 namespace SharpGLTF
@@ -34,6 +35,13 @@ namespace SharpGLTF
         [VertexAttribute(CLASSIFICATIONATTRIBUTENAME, EncodingType.FLOAT, false)]
         public float Classification;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>("COLOR_0", new AttributeFormat(DimensionType.VEC4, EncodingType.UNSIGNED_BYTE, true));
+            yield return new KeyValuePair<string, AttributeFormat>(INTENSITYATTRIBUTENAME, new AttributeFormat(DimensionType.SCALAR));
+            yield return new KeyValuePair<string, AttributeFormat>(CLASSIFICATIONATTRIBUTENAME, new AttributeFormat(DimensionType.SCALAR));
+        }
+
         public int MaxColors => 1;
 
         public int MaxTextCoords => 0;

+ 6 - 0
tests/SharpGLTF.Cesium.Tests/VertexWithFeatureId.cs

@@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis;
 using System.Numerics;
 
 using SharpGLTF.Geometry.VertexTypes;
+using SharpGLTF.Memory;
 using SharpGLTF.Schema2;
 
 namespace SharpGLTF
@@ -30,6 +31,11 @@ namespace SharpGLTF
         [VertexAttribute(CUSTOMATTRIBUTENAME, EncodingType.FLOAT, false)]
         public float BatchId;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>(CUSTOMATTRIBUTENAME, new AttributeFormat(DimensionType.SCALAR));            
+        }
+
         public int MaxColors => 0;
 
         public int MaxTextCoords => 0;

+ 9 - 0
tests/SharpGLTF.Cesium.Tests/VertexWithFeatureIds.cs

@@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis;
 using System.Numerics;
 
 using SharpGLTF.Geometry.VertexTypes;
+using SharpGLTF.Memory;
 using SharpGLTF.Schema2;
 
 namespace SharpGLTF
@@ -30,6 +31,12 @@ namespace SharpGLTF
         [VertexAttribute(FEATUREID1ATTRIBUTENAME, EncodingType.FLOAT, false)]
         public float FeatureId1;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {
+            yield return new KeyValuePair<string, AttributeFormat>(FEATUREID0ATTRIBUTENAME, new AttributeFormat(DimensionType.SCALAR));
+            yield return new KeyValuePair<string, AttributeFormat>(FEATUREID1ATTRIBUTENAME, new AttributeFormat(DimensionType.SCALAR));
+        }
+
         public int MaxColors => 0;
 
         public int MaxTextCoords => 0;
@@ -82,5 +89,7 @@ namespace SharpGLTF
         {
             throw new NotImplementedException();
         }
+
+        
     }
 }

+ 17 - 1
tests/SharpGLTF.Toolkit.Tests/Geometry/VertexTypes/CustomVertices.cs

@@ -4,6 +4,9 @@ using System.Diagnostics.CodeAnalysis;
 using System.Numerics;
 using System.Text;
 
+using SharpGLTF.Memory;
+using SharpGLTF.Schema2;
+
 namespace SharpGLTF.Geometry.VertexTypes
 {
     #if NET6_0_OR_GREATER
@@ -58,6 +61,13 @@ namespace SharpGLTF.Geometry.VertexTypes
         [VertexAttribute("TEXCOORD_0")]
         public Vector2 TexCoord;
 
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {            
+            yield return new KeyValuePair<string, AttributeFormat>("COLOR_0", new AttributeFormat(DimensionType.VEC4, EncodingType.UNSIGNED_BYTE, true));
+            yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_0", new AttributeFormat(DimensionType.VEC2));
+            yield return new KeyValuePair<string, AttributeFormat>(CUSTOMATTRIBUTENAME, new AttributeFormat(DimensionType.SCALAR));
+        }
+
         public int MaxColors => 1;
 
         public int MaxTextCoords => 1;
@@ -172,7 +182,13 @@ namespace SharpGLTF.Geometry.VertexTypes
         public Single CustomId0;
 
         [VertexAttribute(CUSTOMATTRIBUTENAME1, Schema2.EncodingType.UNSIGNED_BYTE, true)]
-        public Vector4 CustomId1;        
+        public Vector4 CustomId1;
+
+        IEnumerable<KeyValuePair<string, AttributeFormat>> IVertexReflection.GetEncodingAttributes()
+        {            
+            yield return new KeyValuePair<string, AttributeFormat>(CUSTOMATTRIBUTENAME0, new AttributeFormat(DimensionType.SCALAR, EncodingType.FLOAT, false));
+            yield return new KeyValuePair<string, AttributeFormat>(CUSTOMATTRIBUTENAME1, new AttributeFormat(DimensionType.VEC4, EncodingType.UNSIGNED_BYTE, true));
+        }
 
         public int MaxColors => 0;