Browse Source

add unit test for custom vertex attribute with name _FEATURE_ID_{attribute}

Bert Temme 2 years ago
parent
commit
8d6371e687

+ 8 - 0
src/SharpGLTF.Cesium/Schema2/MeshExtMeshFeatures.cs

@@ -61,6 +61,14 @@ namespace SharpGLTF.Schema2
             _nullFeatureId = nullFeatureId;
             _texture = texture;
         }
+
+        public int? Attribute
+        {
+            get
+            {
+                return _attribute;
+            }
+        }
     }
 
     public static class ExtMeshFeatures

+ 16 - 0
src/SharpGLTF.Cesium/Validator.cs

@@ -0,0 +1,16 @@
+using SharpGLTF.Schema2;
+
+namespace SharpGLTF
+{
+    internal static class Validator
+    {
+        internal static void ValidateAccessor(ModelRoot model, Accessor accessor)
+        {
+            Guard.NotNull(accessor, nameof(accessor));
+            Guard.MustShareLogicalParent(model, "this", accessor, nameof(accessor));
+            Guard.IsTrue(accessor.Encoding == EncodingType.UNSIGNED_INT, nameof(accessor));
+            Guard.IsTrue(accessor.Dimensions == DimensionType.SCALAR, nameof(accessor));
+            Guard.IsFalse(accessor.Normalized, nameof(accessor));
+        }
+    }
+}

+ 35 - 9
tests/SharpGLTF.Cesium.Tests/ExtMeshFeaturesTests.cs

@@ -25,38 +25,55 @@ namespace SharpGLTF.Cesium
         {
             TestContext.CurrentContext.AttachGltfValidatorLinks();
 
+            // Create a triangle with feature ID custom vertex attribute
+            var featureId = 100;
             var material = MaterialBuilder.CreateDefault();
-            var mesh = new MeshBuilder<VertexPosition>("mesh");
-
+            var mesh = new MeshBuilder<VertexPositionNormal, VertexWithFeatureId, VertexEmpty>("mesh");
             var prim = mesh.UsePrimitive(material);
-            prim.AddTriangle(new VertexPosition(-10, 0, 0), new VertexPosition(10, 0, 0), new VertexPosition(0, 10, 0));
 
-            var scene = new SceneBuilder();
+            // All the vertices in the triangle have the same feature ID
+            var vt0 = GetVertexBuilderWithFeatureId(new Vector3(-10, 0, 0), new Vector3(0, 0, 1), featureId);
+            var vt1 = GetVertexBuilderWithFeatureId(new Vector3(10, 0, 0), new Vector3(0, 0, 1), featureId);
+            var vt2 = GetVertexBuilderWithFeatureId(new Vector3(0, 10, 0), new Vector3(0, 0, 1), featureId);
 
+            prim.AddTriangle(vt0, vt1, vt2);
+            var scene = new SceneBuilder();
             scene.AddRigidMesh(mesh, Matrix4x4.Identity);
-
             var model = scene.ToGltf2();
 
+            // Add feature ID extension
             // See sample https://github.com/CesiumGS/glTF/tree/proposal-EXT_mesh_features/extensions/2.0/Vendor/EXT_mesh_features#feature-id-by-vertex
 
-            // Feature ID by attribute
+            // Method 1: Feature ID by attribute
             var featureIdAttribute = new MeshExtMeshFeatureID(2, 0);
 
-            // Feature ID by Texture coordinates
+            // Method 2: Feature ID by Texture coordinates
             var texture = new MeshExtMeshFeatureIDTexture(new List<int>() { 0 }, 0, 0);
             var featureIdTexture = new MeshExtMeshFeatureID(3, nullFeatureId: 0, texture: texture);
 
-            // Feature ID with property table
+            // Method 3: Feature ID with property table
             var featureIdPropertyTable = new MeshExtMeshFeatureID(3, nullFeatureId: 0, texture: texture,propertyTable:1, label:"classification");
 
+            // Set the FeatureIds
             var featureIds = new List<MeshExtMeshFeatureID>() { featureIdAttribute, featureIdTexture, featureIdPropertyTable };
             model.LogicalMeshes[0].Primitives[0].SetFeatureIds(featureIds);
 
+            // Validate the FeatureIds
             var cesiumExtMeshFeaturesExtension = (MeshExtMeshFeatures)model.LogicalMeshes[0].Primitives[0].Extensions.FirstOrDefault();
             Assert.NotNull(cesiumExtMeshFeaturesExtension.FeatureIds);
 
             Assert.IsTrue(cesiumExtMeshFeaturesExtension.FeatureIds.Equals(featureIds));
-
+            
+            // Check there should be a custom vertex attribute with name _FEATURE_ID_{attribute}
+            var attribute = cesiumExtMeshFeaturesExtension.FeatureIds[0].Attribute;
+            Assert.IsTrue(attribute == 0);
+            var primitive = model.LogicalMeshes[0].Primitives[0];
+            var featureIdVertexAccessor = primitive.GetVertexAccessor($"_FEATURE_ID_{attribute}");
+            Assert.NotNull(featureIdVertexAccessor);
+            var items = featureIdVertexAccessor.AsScalarArray();
+            Assert.AreEqual(items, new List<int> { featureId, featureId, featureId });
+
+            // Todo check: Add check for Texture?
             var ctx = new ValidationResult(model, ValidationMode.Strict, true);
 
             model.ValidateContent(ctx.GetContext());
@@ -65,5 +82,14 @@ namespace SharpGLTF.Cesium
             scene.AttachToCurrentTest("cesium_ext_mesh_features.plotly");
         }
 
+
+        private static VertexBuilder<VertexPositionNormal, VertexWithFeatureId, VertexEmpty> GetVertexBuilderWithFeatureId(Vector3 position, Vector3 normal, int featureid)
+        {
+            var vp0 = new VertexPositionNormal(position, normal);
+            var vb0 = new VertexBuilder<VertexPositionNormal, VertexWithFeatureId, VertexEmpty>(vp0, featureid);
+            return vb0;
+        }
+
+
     }
 }

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

@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Numerics;
+
+using SharpGLTF.Geometry.VertexTypes;
+using SharpGLTF.Schema2;
+
+namespace SharpGLTF
+{
+    [System.Diagnostics.DebuggerDisplay("𝐂:{Color} 𝐔𝐕:{TexCoord}")]
+    public struct VertexWithFeatureId : IVertexCustom
+    {
+        public static implicit operator VertexWithFeatureId(float batchId)
+        {
+            return new VertexWithFeatureId(batchId);
+        }
+
+        public VertexWithFeatureId(float batchId)
+        {
+            BatchId = batchId;
+        }
+
+        public const string CUSTOMATTRIBUTENAME = "_FEATURE_ID_0";
+
+        [VertexAttribute(CUSTOMATTRIBUTENAME, EncodingType.FLOAT, false)]
+        public float BatchId;
+
+        public int MaxColors => 0;
+
+        public int MaxTextCoords => 0;
+
+        public IEnumerable<string> CustomAttributes => throw new NotImplementedException();
+
+        public void SetColor(int setIndex, Vector4 color) { }
+
+        public void SetTexCoord(int setIndex, Vector2 coord) { }
+
+        public Vector4 GetColor(int index) { throw new ArgumentOutOfRangeException(nameof(index)); }
+
+        public Vector2 GetTexCoord(int index) { throw new ArgumentOutOfRangeException(nameof(index)); }
+
+        public void Validate() { }
+
+        public object GetCustomAttribute(string attributeName)
+        {
+            return attributeName == CUSTOMATTRIBUTENAME ? (Object)BatchId : null;
+        }
+
+        public bool TryGetCustomAttribute(string attribute, out object value)
+        {
+            if (attribute != CUSTOMATTRIBUTENAME) { value = null; return false; }
+            value = BatchId; return true;
+        }
+
+        public void SetCustomAttribute(string attributeName, object value)
+        {
+            throw new NotImplementedException();
+        }
+
+        public VertexMaterialDelta Subtract(IVertexMaterial baseValue)
+        {
+            throw new NotImplementedException();
+        }
+
+        public void Add(in VertexMaterialDelta delta)
+        {
+            throw new NotImplementedException();
+        }
+    }
+}