Prechádzať zdrojové kódy

add vector2/vector3/vector4 attributes

Bert Temme 2 rokov pred
rodič
commit
0feba609ed

+ 55 - 3
src/SharpGLTF.Cesium/BinaryTable.cs

@@ -2,6 +2,7 @@
 using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
+using System.Numerics;
 using System.Runtime.InteropServices;
 using System.Text;
 
@@ -22,15 +23,27 @@ namespace SharpGLTF
         public static byte[] GetBytes<T>(IReadOnlyList<T> values)
         {
             Guard.IsTrue(values.Count > 0, nameof(values), "values must have at least one element");
-            
+
             if (typeof(T) == typeof(string))
             {
                 var res = string.Join("", values);
                 return Encoding.UTF8.GetBytes(res);
             }
+            else if (typeof(T) == typeof(Vector2))
+            {
+                return Vector2ToBytes(values);
+            }
+            else if (typeof(T) == typeof(Vector3))
+            {
+                return Vector3ToBytes(values);
+            }
+            else if (typeof(T) == typeof(Vector4))
+            {
+                return Vector4ToBytes(values);
+            }
             else if (typeof(T).IsPrimitive)
             {
-                if(typeof(T) == typeof(bool))
+                if (typeof(T) == typeof(bool))
                 {
                     var bits = new BitArray(values.Cast<bool>().ToArray());
                     byte[] ret = new byte[(bits.Length - 1) / 8 + 1];
@@ -45,12 +58,51 @@ namespace SharpGLTF
             }
             else
             {
-                // other types (like enum, mat2, mat3, mat4, vec2, vec3, vec4, array (fixed length, variable length)) are not implemented
+                // other types (like mat2, mat3, mat4) are not implemented
                 // see https://github.com/CesiumGS/3d-tiles/tree/main/specification/Metadata#binary-table-format
                 throw new NotImplementedException();
             }
         }
 
+        private static byte[] Vector2ToBytes<T>(IReadOnlyList<T> values)
+        {
+            var result = new byte[values.Count * 8];
+            for (int i = 0; i < values.Count; i++)
+            {
+                var vec = (Vector2)(object)values[i];
+                Buffer.BlockCopy(BitConverter.GetBytes(vec.X), 0, result, i * 8, 4);
+                Buffer.BlockCopy(BitConverter.GetBytes(vec.Y), 0, result, i * 8 + 4, 4);
+            }
+            return result;
+        }
+
+        private static byte[] Vector3ToBytes<T>(IReadOnlyList<T> values)
+        {
+            var result = new byte[values.Count * 12];
+            for (int i = 0; i < values.Count; i++)
+            {
+                var vec = (Vector3)(object)values[i];
+                Buffer.BlockCopy(BitConverter.GetBytes(vec.X), 0, result, i * 12, 4);
+                Buffer.BlockCopy(BitConverter.GetBytes(vec.Y), 0, result, i * 12 + 4, 4);
+                Buffer.BlockCopy(BitConverter.GetBytes(vec.Z), 0, result, i * 12 + 8, 4);
+            }
+            return result;
+        }
+
+        private static byte[] Vector4ToBytes<T>(IReadOnlyList<T> values)
+        {
+            var result = new byte[values.Count * 16];
+            for (int i = 0; i < values.Count; i++)
+            {
+                var vec = (Vector4)(object)values[i];
+                Buffer.BlockCopy(BitConverter.GetBytes(vec.X), 0, result, i * 16, 4);
+                Buffer.BlockCopy(BitConverter.GetBytes(vec.Y), 0, result, i * 16 + 4, 4);
+                Buffer.BlockCopy(BitConverter.GetBytes(vec.Z), 0, result, i * 16 + 8, 4);
+                Buffer.BlockCopy(BitConverter.GetBytes(vec.W), 0, result, i * 16 + 12, 4);
+            }
+            return result;
+        }
+
         public static List<int> GetStringOffsets(List<string> values)
         {
             var offsets = new List<int>() { 0 };

+ 0 - 6
src/SharpGLTF.Cesium/Schema2/EXTStructuralMetaDataRoot.cs

@@ -104,10 +104,6 @@ namespace SharpGLTF.Schema2
             {
                 Guard.IsTrue(schema.Classes[propertyTable.Class].Properties.ContainsKey(property.Key), nameof(propertyTable.Properties), $"Property {property.Key} must be defined in schema");
             }
-
-            // check if schema class property has type of enum, then the schema enum based on enumtype must be defined
-            // foreach(var )
-
         }
 
         public static PropertyTableProperty GetArrayPropertyTableProperty<T>(this ModelRoot model, List<List<T>> values, bool CreateArrayOffsets = true)
@@ -434,7 +430,6 @@ namespace SharpGLTF.Schema2
             set { _normalized = value; }
         }
 
-        // add array property
         public bool? Array
         {
             get { return _array; }
@@ -447,7 +442,6 @@ namespace SharpGLTF.Schema2
             get { return _count; }
             set { _count = value; }
         }
-
     }
 
     public partial class PropertyTable

+ 29 - 0
tests/SharpGLTF.Cesium.Tests/BinaryTableTests.cs

@@ -7,6 +7,35 @@ namespace SharpGLTF
 {
     public class BinaryTableTests
     {
+        [Test]
+        public void ConvertVector2ToBytes()
+        {
+            var values = new List<System.Numerics.Vector2>();
+            values.Add(new System.Numerics.Vector2(0, 1));
+            values.Add(new System.Numerics.Vector2(2, 3));
+            var bytes = BinaryTable.GetBytes(values);
+            Assert.That(bytes.Length, Is.EqualTo(BinaryTable.GetSize<System.Numerics.Vector2>() * 2));
+        }
+
+        [Test]
+        public void ConvertVector3ToBytes()
+        {
+            var values = new List<System.Numerics.Vector3>();
+            values.Add(new System.Numerics.Vector3(0, 1, 2));
+            values.Add(new System.Numerics.Vector3(3, 4, 5));
+            var bytes = BinaryTable.GetBytes(values);
+            Assert.That(bytes.Length, Is.EqualTo(BinaryTable.GetSize<System.Numerics.Vector3>() * 2));
+        }
+
+        [Test]
+        public void ConvertVector4ToBytes()
+        {
+            var values = new List<System.Numerics.Vector4>();
+            values.Add(new System.Numerics.Vector4(0, 1, 2, 3));
+            values.Add(new System.Numerics.Vector4(4, 5, 6, 7));
+            var bytes = BinaryTable.GetBytes(values);
+            Assert.That(bytes.Length, Is.EqualTo(BinaryTable.GetSize<System.Numerics.Vector4>() * 2));
+        }
 
         [Test]
         public void TestGetArrayOffset()

+ 108 - 51
tests/SharpGLTF.Cesium.Tests/ExtStructuralMetadataTests.cs

@@ -20,8 +20,65 @@ namespace SharpGLTF.Cesium
             CesiumExtensions.RegisterExtensions();
         }
 
+        [Test(Description = "ext_structural_metadata with FeatureIdAttributeAndPropertyTable")]
+        // sample see https://github.com/CesiumGS/3d-tiles-samples/tree/main/glTF/EXT_structural_metadata/FeatureIdAttributeAndPropertyTable
+        public void FeatureIdAndPropertyTableTest()
+        {
+            TestContext.CurrentContext.AttachGltfValidatorLinks();
+            var material = MaterialBuilder.CreateDefault().WithDoubleSide(true);
+            var mesh = new MeshBuilder<VertexPosition, VertexWithFeatureId, VertexEmpty>("mesh");
+            var prim = mesh.UsePrimitive(material);
+
+            // All the vertices in the triangle have the same feature ID
+            var vt0 = VertexBuilder.GetVertexWithFeatureId(new Vector3(-1, 0, 0), new Vector3(0, 0, 1), 0);
+            var vt1 = VertexBuilder.GetVertexWithFeatureId(new Vector3(1, 0, 0), new Vector3(0, 0, 1), 0);
+            var vt2 = VertexBuilder.GetVertexWithFeatureId(new Vector3(0, 1, 0), new Vector3(0, 0, 1), 0);
+
+            prim.AddTriangle(vt0, vt1, vt2);
+
+            var scene = new SceneBuilder();
+            scene.AddRigidMesh(mesh, Matrix4x4.Identity);
+
+            var model = scene.ToGltf2();
+
+            var featureId = new MeshExtMeshFeatureID(1, 0, 0);
+            model.LogicalMeshes[0].Primitives[0].SetFeatureId(featureId);
+
+            var schema = new StructuralMetadataSchema();
+            schema.Id = "FeatureIdAttributeAndPropertyTableSchema";
+
+            var exampleMetadataClass = new StructuralMetadataClass();
+            exampleMetadataClass.Name = "Example metadata class";
+            exampleMetadataClass.Description = "An example metadata class";
+
+            var vector3Property = new ClassProperty();
+            vector3Property.Name = "Example VEC3 FLOAT32 property";
+            vector3Property.Description = "An example property, with type VEC3, with component type FLOAT32";
+            vector3Property.Type = ElementType.VEC3;
+            vector3Property.ComponentType = DataType.FLOAT32;
+
+            exampleMetadataClass.Properties.Add("example_VEC3_FLOAT32", vector3Property);
+
+            schema.Classes.Add("exampleMetadataClass", exampleMetadataClass);
+
+            var vector3List = new List<Vector3>() { new Vector3(3, 3.0999999046325684f, 3.200000047683716f) };
+
+            var vector3PropertyTableProperty = model.GetPropertyTableProperty(vector3List);
+
+            var examplePropertyTable = new PropertyTable("exampleMetadataClass", 1, "Example property table");
+
+            examplePropertyTable.Properties.Add("example_VEC3_FLOAT32", vector3PropertyTableProperty);
+
+            model.SetPropertyTable(examplePropertyTable, schema);
+
+            var ctx = new ValidationResult(model, ValidationMode.Strict, true);
+            model.AttachToCurrentTest("cesium_ext_structural_metadata_featureid_attribute_and_property_table.glb");
+            model.AttachToCurrentTest("cesium_ext_structural_metadata_featureid_attribute_and_property_table.gltf");
+            model.AttachToCurrentTest("cesium_ext_structural_metadata_featureid_attribute_and_property_table.plotly");
+        }
+
         [Test(Description = "ext_structural_metadata with complex types")]
-        // sample see https://github.com/CesiumGS/3d-tiles-samples/blob/main/glTF/EXT_structural_metadata/ComplexTypes/ComplexTypes.gltf
+        // sample see https://github.com/CesiumGS/3d-tiles-samples/blob/main/glTF/EXT_structural_metadata/ComplexTypes/
         public void ComplexTypesTest()
         {
             TestContext.CurrentContext.AttachGltfValidatorLinks();
@@ -141,7 +198,7 @@ namespace SharpGLTF.Cesium
         }
 
         [Test(Description = "ext_structural_metadata with multiple classes")]
-        // Sample see https://github.com/CesiumGS/3d-tiles-samples/blob/main/glTF/EXT_structural_metadata/MultipleClasses/MultipleClasses.gltf
+        // Sample see https://github.com/CesiumGS/3d-tiles-samples/blob/main/glTF/EXT_structural_metadata/MultipleClasses/
         public void MultipleClassesTest()
         {
             var material = MaterialBuilder.CreateDefault().WithDoubleSide(true);
@@ -195,6 +252,55 @@ namespace SharpGLTF.Cesium
             model.AttachToCurrentTest("cesium_ext_structural_metadata_multiple_classes.plotly");
         }
 
+        [Test(Description = "ext_structural_metadata with pointcloud and custom attributes")]
+        // Sample see https://github.com/CesiumGS/3d-tiles-samples/blob/main/glTF/EXT_structural_metadata/PropertyAttributesPointCloud/
+
+        public void CreatePointCloudWithCustomAttributesTest()
+        {
+            var material = new MaterialBuilder("material1").WithUnlitShader();
+            var mesh = new MeshBuilder<VertexPosition, VertexPointcloud, VertexEmpty>("mesh");
+            var pointCloud = mesh.UsePrimitive(material, 1);
+            var redColor = new Vector4(1f, 0f, 0f, 1f);
+            var rand = new Random();
+            for (var x = -10; x < 10; x++)
+            {
+                for (var y = -10; y < 10; y++)
+                {
+                    for (var z = -10; z < 10; z++)
+                    {
+                        // intensity values is based on x-axis values
+                        // classification of points is 0 or 1 (random)
+                        var vt0 = VertexBuilder.GetVertexPointcloud(new Vector3(x, y, z), redColor, x, rand.Next(0, 2));
+
+                        pointCloud.AddPoint(vt0);
+                    }
+                }
+            }
+            var model = ModelRoot.CreateModel();
+            model.CreateMeshes(mesh);
+
+            // create a scene, a node, and assign the first mesh (the terrain)
+            model.UseScene("Default")
+                .CreateNode().WithMesh(model.LogicalMeshes[0]);
+
+            var propertyAttribute = new Schema2.PropertyAttribute();
+            propertyAttribute.Class = "exampleMetadataClass";
+            var intensityProperty = new PropertyAttributeProperty();
+            intensityProperty.Attribute = "_INTENSITY";
+            var classificationProperty = new PropertyAttributeProperty();
+            classificationProperty.Attribute = "_CLASSIFICATION";
+            propertyAttribute.Properties["intensity"] = intensityProperty;
+            propertyAttribute.Properties["classification"] = classificationProperty;
+
+            var schemaUri = new Uri("MetadataSchema.json", UriKind.Relative);
+            model.SetPropertyAttribute(propertyAttribute, schemaUri);
+            var ctx = new ValidationResult(model, ValidationMode.Strict, true);
+            model.AttachToCurrentTest("cesium_ext_structural_metadata_with_pointcloud_attributes.glb");
+            model.AttachToCurrentTest("cesium_ext_structural_metadata_with_pointcloud_attributes.gltf");
+            model.AttachToCurrentTest("cesium_ext_structural_metadata_with_pointcloud_attributes.plotly");
+        }
+
+
         private static PropertyTable GetFirstPropertyTable(ModelRoot model)
         {
             var firstPropertyTable = new PropertyTable("exampleMetadataClassA", 1, "First example property table");
@@ -264,55 +370,6 @@ namespace SharpGLTF.Cesium
             return classA;
         }
 
-        [Test(Description = "ext_structural_metadata with pointcloud and custom attributes")]
-        // Sample see https://github.com/CesiumGS/3d-tiles-samples/blob/main/glTF/EXT_structural_metadata/PropertyAttributesPointCloud/PropertyAttributesPointCloudHouse.gltf
-
-        public void CreatePointCloudWithCustomAttributesTest()
-        {
-            var material = new MaterialBuilder("material1").WithUnlitShader();
-            var mesh = new MeshBuilder<VertexPosition, VertexPointcloud, VertexEmpty>("mesh");
-            var pointCloud = mesh.UsePrimitive(material, 1);
-            var redColor = new Vector4(1f, 0f, 0f, 1f);
-            var rand = new Random();
-            for (var x = -10; x < 10; x++)
-            {
-                for (var y = -10; y < 10; y++)
-                {
-                    for (var z = -10; z < 10; z++)
-                    {
-                        // intensity values is based on x-axis values
-                        // classification of points is 0 or 1 (random)
-                        var vt0 = VertexBuilder.GetVertexPointcloud(new Vector3(x, y, z), redColor, x, rand.Next(0, 2));
-
-                        pointCloud.AddPoint(vt0);
-                    }
-                }
-            }
-            var model = ModelRoot.CreateModel();
-            model.CreateMeshes(mesh);
-
-            // create a scene, a node, and assign the first mesh (the terrain)
-            model.UseScene("Default")
-                .CreateNode().WithMesh(model.LogicalMeshes[0]);
-
-            var propertyAttribute = new Schema2.PropertyAttribute();
-            propertyAttribute.Class = "exampleMetadataClass";
-            var intensityProperty = new PropertyAttributeProperty();
-            intensityProperty.Attribute = "_INTENSITY";
-            var classificationProperty = new PropertyAttributeProperty();
-            classificationProperty.Attribute = "_CLASSIFICATION";
-            propertyAttribute.Properties["intensity"] = intensityProperty;
-            propertyAttribute.Properties["classification"] = classificationProperty;
-
-            var schemaUri = new Uri("MetadataSchema.json", UriKind.Relative);
-            model.SetPropertyAttribute(propertyAttribute, schemaUri );
-            var ctx = new ValidationResult(model, ValidationMode.Strict, true);
-            model.AttachToCurrentTest("cesium_ext_structural_metadata_with_pointcloud_attributes.glb");
-            model.AttachToCurrentTest("cesium_ext_structural_metadata_with_pointcloud_attributes.gltf");
-            model.AttachToCurrentTest("cesium_ext_structural_metadata_with_pointcloud_attributes.plotly");
-        }
-
-
         [Test(Description = "First test with ext_structural_metadata")]
         public void TriangleWithMetadataTest()
         {