فهرست منبع

Improving Custom vertex attribute support [experimental]

Vicente Penades 6 سال پیش
والد
کامیت
722f906b32

+ 5 - 3
src/SharpGLTF.Toolkit/Geometry/MeshBuilderToolkit.cs

@@ -25,14 +25,16 @@ namespace SharpGLTF.Geometry
     {
         public static Schema2.EncodingType GetOptimalIndexEncoding<TMaterial>(this IEnumerable<IMeshBuilder<TMaterial>> meshes)
         {
-            var maxIndex = meshes
+            var indices = meshes
                 .SelectMany(item => item.Primitives)
                 .Where(item => item.VerticesPerPrimitive >= 2) // points will never use index buffers
-                .SelectMany(prim => prim.GetIndices())
-                .Max();
+                .SelectMany(prim => prim.GetIndices());
+
+            var maxIndex = indices.Any() ? indices.Max() : 0;
 
             return maxIndex < 65535 ? Schema2.EncodingType.UNSIGNED_SHORT : Schema2.EncodingType.UNSIGNED_INT;
         }
+
         public static IMeshBuilder<TMaterial> CreateMeshBuilderFromVertexAttributes<TMaterial>(params string[] vertexAttributes)
         {
             Type meshType = GetMeshBuilderType(typeof(TMaterial), vertexAttributes);

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

@@ -34,6 +34,8 @@ namespace SharpGLTF.Geometry.VertexTypes
 
         (int, float) IVertexSkinning.GetJointBinding(int index) { throw new ArgumentOutOfRangeException(nameof(index)); }
 
+        public object GetCustomAttribute(string attributeName) { return null; }
+
         [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
         Vector4 IVertexSkinning.JointsLow => Vector4.Zero;
         [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]

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

@@ -125,9 +125,9 @@ namespace SharpGLTF.Geometry.VertexTypes
             src.TryGetNormal(out this.Normal);
         }
 
-        public static implicit operator VertexPositionNormal((Vector3, Vector3) posnrm)
+        public static implicit operator VertexPositionNormal((Vector3, Vector3) tuple)
         {
-            return new VertexPositionNormal(posnrm.Item1, posnrm.Item2);
+            return new VertexPositionNormal(tuple.Item1, tuple.Item2);
         }
 
         #endregion
@@ -203,6 +203,11 @@ namespace SharpGLTF.Geometry.VertexTypes
             src.TryGetTangent(out this.Tangent);
         }
 
+        public static implicit operator VertexPositionNormalTangent((Vector3, Vector3, Vector4) tuple)
+        {
+            return new VertexPositionNormalTangent(tuple.Item1, tuple.Item2, tuple.Item3);
+        }
+
         #endregion
 
         #region data

+ 38 - 2
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexMaterial.cs

@@ -18,6 +18,8 @@ namespace SharpGLTF.Geometry.VertexTypes
 
         void SetColor(int setIndex, Vector4 color);
         void SetTexCoord(int setIndex, Vector2 coord);
+
+        Object GetCustomAttribute(string attributeName);
     }
 
     /// <summary>
@@ -64,6 +66,8 @@ namespace SharpGLTF.Geometry.VertexTypes
 
         void IVertexMaterial.SetTexCoord(int setIndex, Vector2 coord) { }
 
+        object IVertexMaterial.GetCustomAttribute(string attributeName) { return null; }
+
         public Vector4 GetColor(int index)
         {
             if (index != 0) throw new ArgumentOutOfRangeException(nameof(index));
@@ -102,6 +106,11 @@ namespace SharpGLTF.Geometry.VertexTypes
             this.Color1 = src.MaxColors > 1 ? src.GetColor(1) : Vector4.One;
         }
 
+        public static implicit operator VertexColor2((Vector4, Vector4) tuple)
+        {
+            return new VertexColor2(tuple.Item1, tuple.Item2);
+        }
+
         #endregion
 
         #region data
@@ -128,6 +137,8 @@ namespace SharpGLTF.Geometry.VertexTypes
 
         void IVertexMaterial.SetTexCoord(int setIndex, Vector2 coord) { }
 
+        object IVertexMaterial.GetCustomAttribute(string attributeName) { return null; }
+
         public Vector4 GetColor(int index)
         {
             if (index == 0) return Color0;
@@ -186,6 +197,8 @@ namespace SharpGLTF.Geometry.VertexTypes
 
         void IVertexMaterial.SetTexCoord(int setIndex, Vector2 coord) { if (setIndex == 0) this.TexCoord = coord; }
 
+        object IVertexMaterial.GetCustomAttribute(string attributeName) { return null; }
+
         public Vector4 GetColor(int index)
         {
             throw new NotSupportedException();
@@ -224,6 +237,11 @@ namespace SharpGLTF.Geometry.VertexTypes
             this.TexCoord1 = src.MaxTextCoords > 1 ? src.GetTexCoord(1) : Vector2.Zero;
         }
 
+        public static implicit operator VertexTexture2((Vector2, Vector2) tuple)
+        {
+            return new VertexTexture2(tuple.Item1, tuple.Item2);
+        }
+
         #endregion
 
         #region data
@@ -250,6 +268,8 @@ namespace SharpGLTF.Geometry.VertexTypes
             if (setIndex == 1) this.TexCoord1 = coord;
         }
 
+        object IVertexMaterial.GetCustomAttribute(string attributeName) { return null; }
+
         public Vector4 GetColor(int index)
         {
             throw new NotSupportedException();
@@ -289,9 +309,9 @@ namespace SharpGLTF.Geometry.VertexTypes
             this.TexCoord = src.MaxTextCoords > 0 ? src.GetTexCoord(0) : Vector2.Zero;
         }
 
-        public static implicit operator VertexColor1Texture1((Vector4, Vector2) coloruv)
+        public static implicit operator VertexColor1Texture1((Vector4, Vector2) tuple)
         {
-            return new VertexColor1Texture1(coloruv.Item1, coloruv.Item2);
+            return new VertexColor1Texture1(tuple.Item1, tuple.Item2);
         }
 
         #endregion
@@ -316,6 +336,8 @@ namespace SharpGLTF.Geometry.VertexTypes
 
         void IVertexMaterial.SetTexCoord(int setIndex, Vector2 coord) { if (setIndex == 0) this.TexCoord = coord; }
 
+        object IVertexMaterial.GetCustomAttribute(string attributeName) { return null; }
+
         public Vector4 GetColor(int index)
         {
             if (index != 0) throw new ArgumentOutOfRangeException(nameof(index));
@@ -357,6 +379,11 @@ namespace SharpGLTF.Geometry.VertexTypes
             this.TexCoord1 = src.MaxTextCoords > 1 ? src.GetTexCoord(1) : Vector2.Zero;
         }
 
+        public static implicit operator VertexColor1Texture2((Vector4, Vector2, Vector2) tuple)
+        {
+            return new VertexColor1Texture2(tuple.Item1, tuple.Item2, tuple.Item3);
+        }
+
         #endregion
 
         #region data
@@ -386,6 +413,8 @@ namespace SharpGLTF.Geometry.VertexTypes
             if (setIndex == 1) this.TexCoord1 = coord;
         }
 
+        object IVertexMaterial.GetCustomAttribute(string attributeName) { return null; }
+
         public Vector4 GetColor(int index)
         {
             if (index != 0) throw new ArgumentOutOfRangeException(nameof(index));
@@ -433,6 +462,11 @@ namespace SharpGLTF.Geometry.VertexTypes
             this.TexCoord1 = src.MaxTextCoords > 1 ? src.GetTexCoord(1) : Vector2.Zero;
         }
 
+        public static implicit operator VertexColor2Texture2((Vector4, Vector4, Vector2, Vector2) tuple)
+        {
+            return new VertexColor2Texture2(tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4);
+        }
+
         #endregion
 
         #region data
@@ -469,6 +503,8 @@ namespace SharpGLTF.Geometry.VertexTypes
             if (setIndex == 1) this.TexCoord1 = coord;
         }
 
+        object IVertexMaterial.GetCustomAttribute(string attributeName) { return null; }
+
         public Vector4 GetColor(int index)
         {
             switch (index)

+ 1 - 1
src/SharpGLTF.Toolkit/Geometry/VertexTypes/VertexUtils.cs

@@ -374,7 +374,7 @@ namespace SharpGLTF.Geometry.VertexTypes
             if (attributeName == "WEIGHTS_0") return v => v.GetSkinning().WeightsLow;
             if (attributeName == "WEIGHTS_1") return v => v.GetSkinning().Weightshigh;
 
-            throw new NotImplementedException();
+            return v => v.GetMaterial().GetCustomAttribute(attributeName);
         }
 
         private static TColumn[] _GetColumn<TVertex, TColumn>(this IReadOnlyList<TVertex> vertices, Func<IVertexBuilder, Object> func)

+ 90 - 0
tests/SharpGLTF.Tests/Geometry/CustomVertices.cs

@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using System.Numerics;
+using System.Text;
+
+using SharpGLTF.Geometry.VertexTypes;
+
+namespace SharpGLTF.Geometry
+{
+    [System.Diagnostics.DebuggerDisplay("𝐂:{Color} 𝐔𝐕:{TexCoord}")]
+    public struct VertexColor1Texture1Custom1 : IVertexMaterial
+    {
+        #region constructors
+
+        public VertexColor1Texture1Custom1(Vector4 color, Vector2 tex, Single batchId)
+        {
+            Color = color;
+            TexCoord = tex;
+            BatchId = batchId;
+        }
+
+        public VertexColor1Texture1Custom1(IVertexMaterial src)
+        {
+            this.Color = src.MaxColors > 0 ? src.GetColor(0) : Vector4.One;
+            this.TexCoord = src.MaxTextCoords > 0 ? src.GetTexCoord(0) : Vector2.Zero;
+
+            if (src is VertexColor1Texture1Custom1 custom)
+            {
+                this.BatchId = custom.BatchId;
+            }
+            else
+            {
+                this.BatchId = 0;
+            }
+        }
+
+        public static implicit operator VertexColor1Texture1Custom1((Vector4 color, Vector2 tex, Single batchId) tuple)
+        {
+            return new VertexColor1Texture1Custom1(tuple.color, tuple.tex, tuple.batchId);
+        }
+
+        #endregion
+
+        #region data
+
+        public const string CUSTOMATTRIBUTENAME = "_CUSTOM_1";
+
+        [VertexAttribute(CUSTOMATTRIBUTENAME, Schema2.EncodingType.FLOAT, false)]
+        public Single BatchId;
+
+        [VertexAttribute("COLOR_0", Schema2.EncodingType.UNSIGNED_BYTE, true)]
+        public Vector4 Color;
+
+        [VertexAttribute("TEXCOORD_0")]
+        public Vector2 TexCoord;
+
+        public int MaxColors => 1;
+
+        public int MaxTextCoords => 1;
+
+        #endregion
+
+        #region API
+
+        void IVertexMaterial.SetColor(int setIndex, Vector4 color) { if (setIndex == 0) this.Color = color; }
+
+        void IVertexMaterial.SetTexCoord(int setIndex, Vector2 coord) { if (setIndex == 0) this.TexCoord = coord; }
+
+        public Vector4 GetColor(int index)
+        {
+            if (index != 0) throw new ArgumentOutOfRangeException(nameof(index));
+            return Color;
+        }
+
+        public Vector2 GetTexCoord(int index)
+        {
+            if (index != 0) throw new ArgumentOutOfRangeException(nameof(index));
+            return TexCoord;
+        }
+
+        public void Validate() { FragmentPreprocessors.ValidateVertexMaterial(this); }
+
+        public object GetCustomAttribute(string attributeName)
+        {
+            return attributeName == CUSTOMATTRIBUTENAME ? (Object)BatchId : null;
+        }
+
+        #endregion
+    }
+}

+ 23 - 0
tests/SharpGLTF.Tests/Geometry/MeshBuilderTests.cs

@@ -239,5 +239,28 @@ namespace SharpGLTF.Geometry
 
             CollectionAssert.AreEqual(new[] { 0, 1, 2, 3, 4, 5, 3, 5, 6 }, prim.GetIndices());
         }
+
+        [Test]
+        public void CreateMeshWithCustomVertexAttribute()
+        {
+            var dmat = Materials.MaterialBuilder.CreateDefault();
+            var mesh = new MeshBuilder<VertexPosition, VertexColor1Texture1Custom1, VertexEmpty>();
+            var prim = mesh.UsePrimitive(dmat);
+
+            prim.AddTriangle
+                (
+                (Vector3.UnitX, (Vector4.One, Vector2.Zero, 1)),
+                (Vector3.UnitY, (Vector4.One, Vector2.Zero, 2)),
+                (Vector3.UnitZ, (Vector4.One, Vector2.Zero, 3))
+                );
+
+            var dstScene = new Schema2.ModelRoot();
+
+            var dstMesh = dstScene.CreateMesh(mesh);
+
+            var batchId = dstMesh.Primitives[0].GetVertexAccessor(VertexColor1Texture1Custom1.CUSTOMATTRIBUTENAME).AsScalarArray();
+
+            CollectionAssert.AreEqual(new float[] { 1, 2, 3 }, batchId);
+        }
     }
 }