ExtStructuralMetadataTests.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. using NUnit.Framework;
  2. using SharpGLTF.Geometry;
  3. using SharpGLTF.Geometry.VertexTypes;
  4. using SharpGLTF.Materials;
  5. using SharpGLTF.Scenes;
  6. using SharpGLTF.Schema2;
  7. using SharpGLTF.Validation;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Numerics;
  11. namespace SharpGLTF.Cesium
  12. {
  13. [Category("Toolkit.Scenes")]
  14. public class ExtStructuralMetadataTests
  15. {
  16. [SetUp]
  17. public void SetUp()
  18. {
  19. CesiumExtensions.RegisterExtensions();
  20. }
  21. [Test(Description = "ext_structural_metadata with multiple classes")]
  22. // Sample see https://github.com/CesiumGS/3d-tiles-samples/blob/main/glTF/EXT_structural_metadata/MultipleClasses/MultipleClasses.gltf
  23. public void MultipleClassesTest()
  24. {
  25. var material = MaterialBuilder.CreateDefault().WithDoubleSide(true);
  26. var mesh = new MeshBuilder<VertexPositionNormal, VertexWithFeatureIds, VertexEmpty>("mesh");
  27. var prim = mesh.UsePrimitive(material);
  28. // All the vertices in the triangle have the same feature ID
  29. var vt0 = VertexBuilder.GetVertexWithFeatureIds(new Vector3(-10, 0, 0), new Vector3(0, 0, 1), 0, 100);
  30. var vt1 = VertexBuilder.GetVertexWithFeatureIds(new Vector3(10, 0, 0), new Vector3(0, 0, 1), 0, 100);
  31. var vt2 = VertexBuilder.GetVertexWithFeatureIds(new Vector3(0, 10, 0), new Vector3(0, 0, 1), 0, 100);
  32. prim.AddTriangle(vt0, vt1, vt2);
  33. var scene = new SceneBuilder();
  34. scene.AddRigidMesh(mesh, Matrix4x4.Identity);
  35. var model = scene.ToGltf2();
  36. // FeatureID 0: featureCount=1, attribute=0, porpertyTable=0
  37. var featureId0Attribute = new MeshExtMeshFeatureID(1, 0, 0);
  38. // FeatureID 1: featureCount=1, attribute=1, porpertyTable=1
  39. var featureId1Attribute = new MeshExtMeshFeatureID(1, 1, 1);
  40. // Set the FeatureIds
  41. var featureIds = new List<MeshExtMeshFeatureID>() { featureId0Attribute, featureId1Attribute };
  42. model.LogicalMeshes[0].Primitives[0].SetFeatureIds(featureIds);
  43. var schema = new StructuralMetadataSchema();
  44. schema.Id = "MultipleClassesSchema";
  45. var classes = new Dictionary<string, StructuralMetadataClass>();
  46. classes["exampleMetadataClassA"] = GetExampleClassA();
  47. classes["exampleMetadataClassB"] = GetExampleClassB();
  48. schema.Classes = classes;
  49. var exampleEnum = new StructuralMetadataEnum();
  50. exampleEnum.Values.Add(new EnumValue() { Name= "ExampleEnumValueA", Value = 0 });
  51. exampleEnum.Values.Add(new EnumValue() { Name = "ExampleEnumValueB", Value = 1 });
  52. exampleEnum.Values.Add(new EnumValue() { Name = "ExampleEnumValueC", Value = 2 });
  53. schema.Enums.Add("exampleEnumType", exampleEnum);
  54. // Todo: create the property tables (First example property table, Second example property table)
  55. // model.SetPropertyAttribute(propertyAttribute, schema);
  56. // todo: add metadata
  57. var ctx = new ValidationResult(model, ValidationMode.Strict, true);
  58. model.AttachToCurrentTest("cesium_ext_structural_metadata_multiple_classes.glb");
  59. model.AttachToCurrentTest("cesium_ext_structural_metadata_multiple_classes.gltf");
  60. model.AttachToCurrentTest("cesium_ext_structural_metadata_multiple_classes.plotly");
  61. }
  62. private static StructuralMetadataClass GetExampleClassB()
  63. {
  64. var classB = new StructuralMetadataClass();
  65. classB.Name = "Example metadata class B";
  66. classB.Description = "Second example metadata class";
  67. var uint16Property = new ClassProperty();
  68. uint16Property.Name = "Example UINT16 property";
  69. uint16Property.Description = "An example property, with component type UINT16";
  70. uint16Property.Type = ElementType.SCALAR;
  71. uint16Property.ComponentType = DataType.UINT16;
  72. classB.Properties.Add("example_UINT16", uint16Property);
  73. var float64Property = new ClassProperty();
  74. float64Property.Name = "Example FLOAT64 property";
  75. float64Property.Description = "An example property, with component type FLOAT64";
  76. float64Property.Type = ElementType.SCALAR;
  77. float64Property.ComponentType = DataType.FLOAT64;
  78. classB.Properties.Add("example_FLOAT64", float64Property);
  79. return classB;
  80. }
  81. private static StructuralMetadataClass GetExampleClassA()
  82. {
  83. var classA = new StructuralMetadataClass();
  84. classA.Name = "Example metadata class A";
  85. classA.Description = "First example metadata class";
  86. var float32Property = new ClassProperty();
  87. float32Property.Name = "Example FLOAT32 property";
  88. float32Property.Description = "An example property, with component type FLOAT32";
  89. float32Property.Type = ElementType.SCALAR;
  90. float32Property.ComponentType = DataType.FLOAT32;
  91. classA.Properties.Add("example_FLOAT32", float32Property);
  92. var int64Property = new ClassProperty();
  93. int64Property.Name = "Example INT64 property";
  94. int64Property.Description = "An example property, with component type INT64";
  95. int64Property.Type = ElementType.SCALAR;
  96. int64Property.ComponentType = DataType.INT64;
  97. classA.Properties.Add("example_INT64", int64Property);
  98. return classA;
  99. }
  100. [Test(Description = "ext_structural_metadata with pointcloud and custom attributes")]
  101. // Sample see https://github.com/CesiumGS/3d-tiles-samples/blob/main/glTF/EXT_structural_metadata/PropertyAttributesPointCloud/PropertyAttributesPointCloudHouse.gltf
  102. public void CreatePointCloudWithCustomAttributesTest()
  103. {
  104. var material = new MaterialBuilder("material1").WithUnlitShader();
  105. var mesh = new MeshBuilder<VertexPosition, VertexPointcloud, VertexEmpty>("mesh");
  106. var pointCloud = mesh.UsePrimitive(material, 1);
  107. var redColor = new Vector4(1f, 0f, 0f, 1f);
  108. var rand = new Random();
  109. for (var x = -10; x < 10; x++)
  110. {
  111. for (var y = -10; y < 10; y++)
  112. {
  113. for (var z = -10; z < 10; z++)
  114. {
  115. // intensity values is based on x-axis values
  116. // classification of points is 0 or 1 (random)
  117. var vt0 = VertexBuilder.GetVertexPointcloud(new Vector3(x, y, z), redColor, x, rand.Next(0, 2));
  118. pointCloud.AddPoint(vt0);
  119. }
  120. }
  121. }
  122. var model = ModelRoot.CreateModel();
  123. model.CreateMeshes(mesh);
  124. // create a scene, a node, and assign the first mesh (the terrain)
  125. model.UseScene("Default")
  126. .CreateNode().WithMesh(model.LogicalMeshes[0]);
  127. var propertyAttribute = new Schema2.PropertyAttribute();
  128. propertyAttribute.Class = "exampleMetadataClass";
  129. var intensityProperty = new PropertyAttributeProperty();
  130. intensityProperty.Attribute = "_INTENSITY";
  131. var classificationProperty = new PropertyAttributeProperty();
  132. classificationProperty.Attribute = "_CLASSIFICATION";
  133. propertyAttribute.Properties["intensity"] = intensityProperty;
  134. propertyAttribute.Properties["classification"] = classificationProperty;
  135. model.SetPropertyAttribute(propertyAttribute, schemaUri: new Uri("MetadataSchema.json", UriKind.Relative));
  136. var ctx = new ValidationResult(model, ValidationMode.Strict, true);
  137. model.AttachToCurrentTest("cesium_ext_structural_metadata_with_pointcloud_attributes.glb");
  138. model.AttachToCurrentTest("cesium_ext_structural_metadata_with_pointcloud_attributes.gltf");
  139. model.AttachToCurrentTest("cesium_ext_structural_metadata_with_pointcloud_attributes.plotly");
  140. }
  141. [Test(Description = "First test with ext_structural_metadata")]
  142. public void TriangleWithMetadataTest()
  143. {
  144. var model = GetTriangleModel();
  145. var schema = GetSampleSchema();
  146. var attribute = new List<int>() { 100 };
  147. var dict = new Dictionary<string, List<int>>();
  148. dict["age"] = attribute;
  149. model.SetPropertyTable(dict, schema: schema);
  150. // create files
  151. var ctx = new ValidationResult(model, ValidationMode.Strict, true);
  152. model.AttachToCurrentTest("cesium_ext_structural_metadata_basic_triangle.glb");
  153. model.AttachToCurrentTest("cesium_ext_structural_metadata_basic_triangle.gltf");
  154. model.AttachToCurrentTest("cesium_ext_structural_metadata_basic_triangle.plotly");
  155. }
  156. private static ModelRoot GetTriangleModel()
  157. {
  158. TestContext.CurrentContext.AttachGltfValidatorLinks();
  159. var material = MaterialBuilder.CreateDefault().WithDoubleSide(true);
  160. var mesh = new MeshBuilder<VertexPosition>("mesh");
  161. var prim = mesh.UsePrimitive(material);
  162. prim.AddTriangle(new VertexPosition(-10, 0, 0), new VertexPosition(10, 0, 0), new VertexPosition(0, 10, 0));
  163. var scene = new SceneBuilder();
  164. scene.AddRigidMesh(mesh, Matrix4x4.Identity);
  165. var model = scene.ToGltf2();
  166. return model;
  167. }
  168. private static StructuralMetadataSchema GetSampleSchema()
  169. {
  170. var schema = new StructuralMetadataSchema();
  171. schema.Id = "schema_001";
  172. schema.Name = "schema 001";
  173. schema.Description = "an example schema";
  174. schema.Version = "3.5.1";
  175. var classes = new Dictionary<string, StructuralMetadataClass>();
  176. var treeClass = new StructuralMetadataClass();
  177. treeClass.Name = "Tree";
  178. treeClass.Description = "Woody, perennial plant.";
  179. classes["tree"] = treeClass;
  180. var ageProperty = new ClassProperty();
  181. ageProperty.Description = "The age of the tree, in years";
  182. ageProperty.Type = ElementType.SCALAR;
  183. ageProperty.ComponentType = DataType.UINT32;
  184. ageProperty.Required = true;
  185. treeClass.Properties.Add("age", ageProperty);
  186. schema.Classes = classes;
  187. return schema;
  188. }
  189. }
  190. }