Răsfoiți Sursa

Merge pull request #175 from bertt/feature/cesium_primitive_outline

Feature/cesium primitive outline
Vicente Penades 2 ani în urmă
părinte
comite
50ba47ccec

+ 30 - 0
build/SharpGLTF.CodeGen/Ext.CESIUM_primitive_outline.cs

@@ -0,0 +1,30 @@
+using SharpGLTF.CodeGen;
+using SharpGLTF.SchemaReflection;
+using System.Collections.Generic;
+
+namespace SharpGLTF
+{
+    class CesiumPrimitiveOutlineExtension : SchemaProcessor
+    {
+        private static string RootSchemaUri => Constants.VendorExtensionPath("CESIUM_primitive_outline", "primitive.CESIUM_primitive_outline.schema.json");
+
+        public override void PrepareTypes(CSharpEmitter newEmitter, SchemaType.Context ctx)
+        {
+            newEmitter.SetRuntimeName("Ext.CESIUM_primitive_outline glTF extension", "CesiumPrimitiveOutline");
+        }
+
+        public override IEnumerable<(string TargetFileName, SchemaType.Context Schema)> Process()
+        {
+            yield return ("Ext.CESIUM_primitive_outline.g", ProcessRoot());
+        }
+
+        private static SchemaType.Context ProcessRoot()
+        {
+            var ctx = SchemaProcessing.LoadSchemaContext(RootSchemaUri);
+            ctx.IgnoredByCodeEmitter("glTF Property");
+            ctx.IgnoredByCodeEmitter("glTF Child of Root Property");
+
+            return ctx;
+        }
+    }
+}

+ 3 - 1
build/SharpGLTF.CodeGen/Program.cs

@@ -41,7 +41,9 @@ namespace SharpGLTF
             processors.Add(new TransmissionExtension());
             processors.Add(new TransmissionExtension());
             processors.Add(new EmissiveStrengthExtension());
             processors.Add(new EmissiveStrengthExtension());
             processors.Add(new SpecularGlossinessExtension());
             processors.Add(new SpecularGlossinessExtension());
-            
+
+            // cesium outlines
+            processors.Add(new CesiumPrimitiveOutlineExtension());
 
 
             // lights
             // lights
             processors.Add(new LightsPunctualExtension());
             processors.Add(new LightsPunctualExtension());

+ 2 - 0
src/SharpGLTF.Core/README.md

@@ -66,6 +66,8 @@ It also handles the way a mesh is brought from its local space to world space, i
 - [ ] [EXT_lights_image_based](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_lights_image_based)
 - [ ] [EXT_lights_image_based](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_lights_image_based)
 - [x] [EXT_texture_webp](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_texture_webp)
 - [x] [EXT_texture_webp](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_texture_webp)
 - [ ] [ADOBE_materials_thin_transparency](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/ADOBE_materials_thin_transparency)
 - [ ] [ADOBE_materials_thin_transparency](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/ADOBE_materials_thin_transparency)
+- [x] [CESIUM_primitive_outline](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Vendor/CESIUM_primitive_outline)
+
 
 
 
 
 
 

+ 56 - 0
src/SharpGLTF.Core/Schema2/Generated/Ext.CESIUM_primitive_outline.g.cs

@@ -0,0 +1,56 @@
+// <auto-generated/>
+
+//------------------------------------------------------------------------------------------------
+//      This file has been programatically generated; DON´T EDIT!
+//------------------------------------------------------------------------------------------------
+
+#pragma warning disable SA1001
+#pragma warning disable SA1027
+#pragma warning disable SA1028
+#pragma warning disable SA1121
+#pragma warning disable SA1205
+#pragma warning disable SA1309
+#pragma warning disable SA1402
+#pragma warning disable SA1505
+#pragma warning disable SA1507
+#pragma warning disable SA1508
+#pragma warning disable SA1652
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Numerics;
+using System.Text.Json;
+
+namespace SharpGLTF.Schema2
+{
+	using Collections;
+
+	/// <summary>
+	/// glTF extension for indicating that some edges of a primitive's triangles should be outlined.
+	/// </summary>
+	partial class CESIUM_primitive_outlineglTFprimitiveextension : ExtraProperties
+	{
+	
+		private Int32? _indices;
+		
+	
+		protected override void SerializeProperties(Utf8JsonWriter writer)
+		{
+			base.SerializeProperties(writer);
+			SerializeProperty(writer, "indices", _indices);
+		}
+	
+		protected override void DeserializeProperty(string jsonPropertyName, ref Utf8JsonReader reader)
+		{
+			switch (jsonPropertyName)
+			{
+				case "indices": _indices = DeserializePropertyValue<Int32?>(ref reader); break;
+				default: base.DeserializeProperty(jsonPropertyName,ref reader); break;
+			}
+		}
+	
+	}
+
+}

+ 2 - 0
src/SharpGLTF.Core/Schema2/gltf.ExtensionsFactory.cs

@@ -49,6 +49,8 @@ namespace SharpGLTF.Schema2
             RegisterExtension<ModelRoot, AgiRootStkMetadata>("AGI_stk_metadata");
             RegisterExtension<ModelRoot, AgiRootStkMetadata>("AGI_stk_metadata");
             RegisterExtension<Node, AgiNodeArticulations>("AGI_articulations");
             RegisterExtension<Node, AgiNodeArticulations>("AGI_articulations");
             RegisterExtension<Node, AgiNodeStkMetadata>("AGI_stk_metadata");
             RegisterExtension<Node, AgiNodeStkMetadata>("AGI_stk_metadata");
+
+            RegisterExtension<MeshPrimitive, CESIUM_primitive_outlineglTFprimitiveextension>("CESIUM_primitive_outline");
         }
         }
 
 
         #endregion
         #endregion

+ 98 - 0
src/SharpGLTF.Core/Schema2/gltf.MeshPrimitive.CESIUM_primitive_outline.cs

@@ -0,0 +1,98 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace SharpGLTF.Schema2
+{
+    partial class CESIUM_primitive_outlineglTFprimitiveextension
+    {
+        private MeshPrimitive meshPrimitive;
+        internal CESIUM_primitive_outlineglTFprimitiveextension(MeshPrimitive meshPrimitive)
+        {
+            this.meshPrimitive = meshPrimitive;
+        }
+
+        public int? Indices
+        {
+            get => _indices;
+            set => _indices = value;
+        }
+
+        protected override void OnValidateContent(Validation.ValidationContext validate)
+        {
+            var outlineAccessor = meshPrimitive.LogicalParent.LogicalParent.LogicalAccessors[(int)_indices];
+            var isValid = CesiumToolkit.ValidateCesiumOutlineIndices(outlineAccessor, meshPrimitive);
+            validate.IsTrue(nameof(_indices), isValid, "Mismatch between accesor indices and MeshPrimitive indices");
+
+            base.OnValidateContent(validate);
+        }
+    }
+
+    partial class MeshPrimitive
+    {
+        public void SetCesiumOutline(Accessor accessor)
+        {
+            if (accessor == null) { RemoveExtensions<CESIUM_primitive_outlineglTFprimitiveextension>(); return; }
+
+            Guard.NotNull(accessor, nameof(accessor));
+            Guard.MustShareLogicalParent(LogicalParent.LogicalParent, "this", accessor, nameof(accessor));
+            Guard.IsTrue(accessor.Encoding == EncodingType.UNSIGNED_INT, nameof(accessor));
+            Guard.IsTrue(accessor.Dimensions == DimensionType.SCALAR, nameof(accessor));
+
+            var ext = UseExtension<CESIUM_primitive_outlineglTFprimitiveextension>();
+            ext.Indices = accessor.LogicalIndex;
+        }
+    }
+
+    public static class CesiumToolkit
+    {
+        /// <summary>
+        /// Creates an accessor to store Cesium outline vertex indices
+        /// </summary>
+        /// <param name="model"></param>
+        /// <param name="outlines"></param>
+        /// <returns></returns>
+        public static Accessor CreateCesiumOutlineAccessor(ModelRoot model, IReadOnlyList<uint> outlines, string name="Cesium outlines")
+        {
+            var outlineBytes = new List<byte>();
+
+            foreach (var bytes in from outline in outlines
+                                  let bytes = BitConverter.GetBytes(outline).ToList()
+                                  select bytes)
+            {
+                outlineBytes.AddRange(bytes);
+            }
+
+            var buffer = model.UseBufferView(outlineBytes.ToArray());
+            var accessor = model.CreateAccessor(name);
+            accessor.SetData(buffer, 0, outlineBytes.Count / 4, DimensionType.SCALAR, EncodingType.UNSIGNED_INT, false);
+            return accessor;
+        }
+
+        /// <summary>
+        /// Checks if all the indices of the Cesium outline accessor are within the range of in the MeshPrimitive indices
+        /// </summary>
+        /// <param name="accessor">Cesium outline accessor</param>
+        /// <param name="meshPrimitive">MeshPrimitive with the CESIUM_primitive_outline extension</param>
+        /// <returns>true all indices are available, false indices are missing </returns>
+        internal static bool ValidateCesiumOutlineIndices(Accessor accessor, MeshPrimitive meshPrimitive)
+        {
+            var cesiumOutlineExtension = meshPrimitive.GetExtension<CESIUM_primitive_outlineglTFprimitiveextension>();
+            if (cesiumOutlineExtension != null)
+            {
+                var accessorIndices = accessor.AsIndicesArray();
+                var meshPrimitiveIndices = meshPrimitive.GetIndices();
+                var maxIndice = meshPrimitiveIndices.Max();
+
+                foreach (var _ in from accessorIndice in accessorIndices
+                                  let contains = accessorIndice <= maxIndice
+                                  where !contains
+                                  select new { })
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+}

+ 36 - 1
tests/SharpGLTF.Toolkit.Tests/Scenes/SceneBuilderTests.cs

@@ -10,6 +10,9 @@ using SharpGLTF.Geometry;
 using SharpGLTF.Geometry.VertexTypes;
 using SharpGLTF.Geometry.VertexTypes;
 using SharpGLTF.Geometry.Parametric;
 using SharpGLTF.Geometry.Parametric;
 using SharpGLTF.Materials;
 using SharpGLTF.Materials;
+using System.Diagnostics;
+using System.Collections.ObjectModel;
+using SharpGLTF.Validation;
 
 
 namespace SharpGLTF.Scenes
 namespace SharpGLTF.Scenes
 {
 {
@@ -22,6 +25,38 @@ namespace SharpGLTF.Scenes
     [Category("Toolkit.Scenes")]
     [Category("Toolkit.Scenes")]
     public partial class SceneBuilderTests
     public partial class SceneBuilderTests
     {
     {
+        [Test(Description = "Creates a simple triangle with Cesium outlining")]
+        public void CreateCesiumOutlineTriangleScene()
+        {
+            TestContext.CurrentContext.AttachGltfValidatorLinks();
+
+            var material = MaterialBuilder.CreateDefault();
+
+            var mesh = new MeshBuilder<VertexPosition>("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();
+
+            scene.AddRigidMesh(mesh, Matrix4x4.Identity);
+
+            var model = scene.ToGltf2();
+
+            var outlines = new ReadOnlyCollection<uint>(new List<uint> { 0, 1, 1, 2, 2, 0});
+            var accessor = CesiumToolkit.CreateCesiumOutlineAccessor(model, outlines);
+            model.LogicalMeshes[0].Primitives[0].SetCesiumOutline(accessor);
+
+            var cesiumOutlineExtension = (CESIUM_primitive_outlineglTFprimitiveextension)model.LogicalMeshes[0].Primitives[0].Extensions.FirstOrDefault();
+            Assert.True(cesiumOutlineExtension.Indices == accessor.LogicalIndex);
+            var ctx = new ValidationResult(model, ValidationMode.Strict, true);
+            model.ValidateContent(ctx.GetContext());
+
+            scene.AttachToCurrentTest("cesium_outline_triangle.glb");
+            scene.AttachToCurrentTest("cesium_outline_triangle.gltf");
+            scene.AttachToCurrentTest("cesium_outline_triangle.plotly");
+        }
+
         [Test(Description ="Creates a simple cube.")]
         [Test(Description ="Creates a simple cube.")]
         public void CreateCubeScene()
         public void CreateCubeScene()
         {            
         {            
@@ -1031,4 +1066,4 @@ namespace SharpGLTF.Scenes
         }
         }
 
 
     }
     }
-}
+}