Bladeren bron

exposed EmissiveStrength to MaterialBuilder

Vicente Penades 3 jaren geleden
bovenliggende
commit
07613502d0

+ 1 - 0
src/SharpGLTF.Core/Schema2/gltf.MaterialParameter.cs

@@ -29,6 +29,7 @@ namespace SharpGLTF.Schema2
 
         NormalScale,
         OcclusionStrength,
+        EmissiveStrength,
 
         MetallicFactor,
         RoughnessFactor,

+ 18 - 3
src/SharpGLTF.Core/Schema2/gltf.MaterialsFactory.cs

@@ -117,7 +117,7 @@ namespace SharpGLTF.Schema2
                 () => _GetOcclusionTexture(false)?.Strength ?? MaterialOcclusionTextureInfo.StrengthDefault,
                 value => _GetOcclusionTexture(true).Strength = value);
 
-            var emissiveParam = new _MaterialParameter<Vector3>(
+            var emissiveFactorParam = new _MaterialParameter<Vector3>(
                 _MaterialParameterKey.RGB,
                 _emissiveFactorDefault,
                 () => this._emissiveFactor.AsValue(_emissiveFactorDefault),
@@ -125,7 +125,7 @@ namespace SharpGLTF.Schema2
 
             yield return new MaterialChannel(this, "Normal", _GetNormalTexture, normalParam);
             yield return new MaterialChannel(this, "Occlusion", _GetOcclusionTexture, occlusionParam);
-            yield return new MaterialChannel(this, "Emissive", _GetEmissiveTexture, emissiveParam);
+            yield return new MaterialChannel(this, "Emissive", _GetEmissiveTexture, emissiveFactorParam, MaterialEmissiveStrength.GetParameter(this));
         }
 
         private MaterialNormalTextureInfo _GetNormalTexture(bool create)
@@ -626,12 +626,27 @@ namespace SharpGLTF.Schema2
             if (_emissiveStrength < _emissiveStrengthMinimum) throw new ArgumentOutOfRangeException(nameof(EmissiveStrength)); 
         }
 
-        public static float DefaultEmissiveStrength => (float)_emissiveStrengthDefault;
+        public const float DefaultEmissiveStrength = (float)_emissiveStrengthDefault;
 
         public float EmissiveStrength
         {
             get => (float)(this._emissiveStrength ?? _emissiveStrengthDefault);
             set => this._emissiveStrength = ((double)value).AsNullable(_emissiveStrengthDefault);
         }
+
+        public static _MaterialParameter<float> GetParameter(Material material)
+        {
+            float _getter() { return material.GetExtension<MaterialEmissiveStrength>()?.EmissiveStrength ?? 1; }
+
+            void _setter(float value)
+            {
+                value = Math.Max((float)_emissiveStrengthMinimum, value);
+
+                if (value == DefaultEmissiveStrength) { material.RemoveExtensions<MaterialEmissiveStrength>(); }
+                else { material.UseExtension<MaterialEmissiveStrength>().EmissiveStrength = value; }
+            }
+
+            return new _MaterialParameter<float>(_MaterialParameterKey.EmissiveStrength, DefaultEmissiveStrength, _getter, _setter);
+        }
     }
 }

+ 7 - 4
src/SharpGLTF.Toolkit/Materials/MaterialBuilder.cs

@@ -318,6 +318,7 @@ namespace SharpGLTF.Materials
         /// Sets <see cref="ShaderStyle"/> to use <see cref="SHADERPBRSPECULARGLOSSINESS"/>.
         /// </summary>
         /// <returns>This <see cref="MaterialBuilder"/>.</returns>
+        [Obsolete("SpecularGlossiness has been deprecated by Khronos")]
         public MaterialBuilder WithSpecularGlossinessShader() { _SetShader(SHADERPBRSPECULARGLOSSINESS); return this; }
 
         public MaterialBuilder WithAlpha(AlphaMode alphaMode = AlphaMode.OPAQUE, Single alphaCutoff = 0.5f)
@@ -424,15 +425,17 @@ namespace SharpGLTF.Materials
             return this;
         }
 
-        public MaterialBuilder WithEmissive(Vector3 rgb)
+        public MaterialBuilder WithEmissive(Vector3 rgb, float strength = 1)
         {
-            return WithChannelParam(KnownChannel.Emissive, KnownProperty.RGB, rgb);
+            WithChannelParam(KnownChannel.Emissive, KnownProperty.EmissiveStrength, strength);
+            WithChannelParam(KnownChannel.Emissive, KnownProperty.RGB, rgb);
+            return this;
         }
 
-        public MaterialBuilder WithEmissive(IMAGEFILE imageFile, Vector3? rgb = null)
+        public MaterialBuilder WithEmissive(IMAGEFILE imageFile, Vector3? rgb = null, float strength = 1)
         {
             WithChannelImage(KnownChannel.Emissive, imageFile);
-            if (rgb.HasValue) WithEmissive(rgb.Value);
+            if (rgb.HasValue) WithEmissive(rgb.Value, strength);
             return this;
         }
 

+ 9 - 2
src/SharpGLTF.Toolkit/Materials/MaterialEnums.cs

@@ -48,15 +48,18 @@ namespace SharpGLTF.Materials
     /// Enumeration of channel properties used in <see cref="ChannelBuilder.Parameters"/>
     /// </summary>
     /// <remarks>
-    /// This enumeration must match <see cref="Schema2.MaterialParameter.Key"/>
+    /// This enumeration must match <see cref="Schema2._MaterialParameterKey"/>
     /// </remarks>
     public enum KnownProperty
     {
+        Unknown = 0,
+
         RGB,
         RGBA,
 
         NormalScale,
         OcclusionStrength,
+        EmissiveStrength,
 
         MetallicFactor,
         RoughnessFactor,
@@ -132,7 +135,11 @@ namespace SharpGLTF.Materials
         {
             switch (key)
             {
-                case KnownChannel.Emissive: yield return new _Property(KnownProperty.RGB, Vector3.Zero); break;
+                case KnownChannel.Emissive:
+                    yield return new _Property(KnownProperty.RGB, Vector3.Zero);
+                    yield return new _Property(KnownProperty.EmissiveStrength, 1f);
+                    break;
+
                 case KnownChannel.Normal: yield return new _Property(KnownProperty.NormalScale, 1f); break;
                 case KnownChannel.Occlusion: yield return new _Property(KnownProperty.OcclusionStrength, 1f); break;
 

+ 121 - 85
tests/SharpGLTF.Toolkit.Tests/Materials/MaterialBuilderTests.cs

@@ -25,15 +25,8 @@ namespace SharpGLTF.Materials
             // at a given time, and non equal at another. Furthermore, it would imply having
             // a hash code that changes over time. As a consequence, it could be impossible
             // to use MaterialBuilder as a dictionary Key.
-            
-            var assetsPath = System.IO.Path.Combine(TestContext.CurrentContext.TestDirectory, "Assets");
-            var tex1 = System.IO.Path.Combine(assetsPath, "shannon.png");
 
-            var srcMaterial = new MaterialBuilder()
-                .WithDoubleSide(true) // notice that DoubleSide enables double face rendering. This is an example, but it's usually NOT NECCESARY.
-                .WithAlpha(AlphaMode.MASK, 0.7f)
-                .WithUnlitShader()
-                .WithBaseColor(tex1, new Vector4(0.7f, 0, 0f, 0.8f));
+            var srcMaterial = _CreateUnlitMaterial();
 
             var clnMaterial = srcMaterial.Clone();
 
@@ -54,115 +47,141 @@ namespace SharpGLTF.Materials
 
         [Test]
         public void CreateUnlit()
+        {
+            var material = _CreateUnlitMaterial();
+
+            Assert.IsTrue(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
+            Assert.IsTrue(MaterialBuilder.AreEqualByContent(material, material.Clone()));
+        }        
+
+        [Test]
+        public void CreateMetallicRoughness()
+        {
+            var material = _CreateMetallicRoughnessMaterial();
+
+            Assert.IsTrue(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
+            Assert.IsTrue(MaterialBuilder.AreEqualByContent(material, material.Clone()));
+        }        
+
+        [Test]
+        public void CreateClearCoat()
+        {
+            var material = _CreateClearCoatMaterial();
+
+            Assert.IsTrue(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
+            Assert.IsTrue(MaterialBuilder.AreEqualByContent(material, material.Clone()));
+        }        
+
+        [Test]
+        public void CreateVolume()
+        {
+            var material = _CreateVolumeMaterial();
+
+            Assert.IsTrue(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
+            Assert.IsTrue(MaterialBuilder.AreEqualByContent(material, material.Clone()));
+        }        
+
+        [Test]
+        public void CreateSpecularGlossiness()
+        {
+            var material = _CreateSpecularGlossinessMaterial();
+
+            Assert.IsTrue(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
+            Assert.IsTrue(MaterialBuilder.AreEqualByContent(material, material.Clone()));
+        }        
+
+        [Test]
+        public void CreateSpecularGlossinessWithFallback()
+        {
+            var material = _CreateSpecularGlossinessMaterialWithFallback();
+
+            // check
+            Assert.IsTrue(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
+            Assert.IsTrue(MaterialBuilder.AreEqualByContent(material, material.Clone()));
+        }
+
+        private static MaterialBuilder _CreateUnlitMaterial()
         {
             var assetsPath = System.IO.Path.Combine(TestContext.CurrentContext.TestDirectory, "Assets");
             var tex1 = System.IO.Path.Combine(assetsPath, "shannon.png");
 
-            var srcMaterial = new MaterialBuilder()
+            var material = new MaterialBuilder("Unlit Material")
                 .WithDoubleSide(true) // notice that DoubleSide enables double face rendering. This is an example, but it's usually NOT NECCESARY.
-                .WithAlpha(AlphaMode.MASK, 0.7f)
-                .WithUnlitShader()
+                .WithAlpha(AlphaMode.MASK, 0.7f);
+
+            material.WithUnlitShader()
                 .WithBaseColor(tex1, new Vector4(0.7f, 0, 0f, 0.8f));
 
-            Assert.IsTrue(MaterialBuilder.AreEqualByContent(srcMaterial, Schema2Roundtrip(srcMaterial)));
-            Assert.IsTrue(MaterialBuilder.AreEqualByContent(srcMaterial, srcMaterial.Clone()));
+            return material;
         }
 
-        [Test]
-        public void CreateMetallicRoughness()
+        private static MaterialBuilder _CreateMetallicRoughnessMaterial()
         {
             var assetsPath = System.IO.Path.Combine(TestContext.CurrentContext.TestDirectory, "Assets");
             var tex1 = System.IO.Path.Combine(assetsPath, "shannon.png");
 
-            var srcMaterial = new MaterialBuilder()                
+            var material = new MaterialBuilder("Metallic Roughness Material")
                 .WithAlpha(AlphaMode.MASK, 0.6f)
-                .WithEmissive(tex1, new Vector3(0.2f, 0.3f, 0.1f))
+                .WithEmissive(tex1, new Vector3(0.2f, 0.3f, 0.1f), 6)
                 .WithNormal(tex1, 0.3f)
-                .WithOcclusion(tex1, 0.4f)
+                .WithOcclusion(tex1, 0.4f);
 
-                .WithMetallicRoughnessShader()
-                    .WithBaseColor(tex1, new Vector4(0.7f, 0, 0f, 0.8f))
-                    .WithMetallicRoughness(tex1, 0.2f, 0.4f);
+            material.WithMetallicRoughnessShader()
+                .WithBaseColor(tex1, new Vector4(0.7f, 0, 0f, 0.8f))
+                .WithMetallicRoughness(tex1, 0.2f, 0.4f);                
 
             // example of setting additional parameters for a given channel.
-            srcMaterial.GetChannel(KnownChannel.BaseColor)
+            material.GetChannel(KnownChannel.BaseColor)
                 .Texture
                 .WithCoordinateSet(1)
                 .WithSampler(TextureWrapMode.CLAMP_TO_EDGE, TextureWrapMode.MIRRORED_REPEAT, TextureMipMapFilter.LINEAR_MIPMAP_LINEAR, TextureInterpolationFilter.NEAREST)
-                .WithTransform(Vector2.One*0.2f, Vector2.One*0.3f,0.1f, 2);
-                
+                .WithTransform(Vector2.One * 0.2f, Vector2.One * 0.3f, 0.1f, 2);
 
-            Assert.IsTrue(MaterialBuilder.AreEqualByContent(srcMaterial, Schema2Roundtrip(srcMaterial)));
-            Assert.IsTrue(MaterialBuilder.AreEqualByContent(srcMaterial, srcMaterial.Clone()));            
+            return material;
         }
 
-        [Test]
-        public void CreateClearCoat()
+        private static MaterialBuilder _CreateVolumeMaterial()
         {
             var assetsPath = System.IO.Path.Combine(TestContext.CurrentContext.TestDirectory, "Assets");
             var tex1 = System.IO.Path.Combine(assetsPath, "shannon.png");
 
-            var srcMaterial = new MaterialBuilder()                
-                .WithAlpha(AlphaMode.MASK, 0.6f)
-                .WithEmissive(tex1, new Vector3(0.2f, 0.3f, 0.1f))
-                .WithNormal(tex1, 0.3f)
-                .WithOcclusion(tex1, 0.4f)
-
-                .WithMetallicRoughnessShader()
-                    .WithBaseColor(tex1, new Vector4(0.7f, 0, 0f, 0.8f))
-                    .WithMetallicRoughness(tex1, 0.2f, 0.4f)
-
-                .WithClearCoat(tex1, 1)
-                .WithClearCoatNormal(tex1)
-                .WithClearCoatRoughness(tex1, 1);
-
-
-            Assert.IsTrue(MaterialBuilder.AreEqualByContent(srcMaterial, Schema2Roundtrip(srcMaterial)));
-            Assert.IsTrue(MaterialBuilder.AreEqualByContent(srcMaterial, srcMaterial.Clone()));
-        }
+            var material = new MaterialBuilder("Volume Material")
+                .WithAlpha(AlphaMode.MASK, 0.6f);
 
-        [Test]
-        public void CreateVolume()
-        {
-            var assetsPath = System.IO.Path.Combine(TestContext.CurrentContext.TestDirectory, "Assets");
-            var tex1 = System.IO.Path.Combine(assetsPath, "shannon.png");
+            material.WithMetallicRoughnessShader()
+                .WithBaseColor(tex1, new Vector4(0.7f, 0, 0f, 0.8f))
+                .WithMetallicRoughness(tex1, 0.2f, 0.4f);
 
-            var srcMaterial = new MaterialBuilder()
-                .WithAlpha(AlphaMode.MASK, 0.6f)
-                .WithMetallicRoughnessShader()
-                    .WithBaseColor(tex1, new Vector4(0.7f, 0, 0f, 0.8f))
-                    .WithMetallicRoughness(tex1, 0.2f, 0.4f)
-
-                .WithVolumeAttenuation(Vector3.One * 0.3f, 0.6f)
+            material.WithVolumeAttenuation(Vector3.One * 0.3f, 0.6f)
                 .WithVolumeThickness(tex1, 0.4f);
 
-            Assert.IsTrue(MaterialBuilder.AreEqualByContent(srcMaterial, Schema2Roundtrip(srcMaterial)));
-            Assert.IsTrue(MaterialBuilder.AreEqualByContent(srcMaterial, srcMaterial.Clone()));
+            return material;
         }
 
-        [Test]
-        public void CreateSpecularGlossiness()
+        private static MaterialBuilder _CreateClearCoatMaterial()
         {
             var assetsPath = System.IO.Path.Combine(TestContext.CurrentContext.TestDirectory, "Assets");
             var tex1 = System.IO.Path.Combine(assetsPath, "shannon.png");
 
-            var srcMaterial = new MaterialBuilder()                
+            var material = new MaterialBuilder("Clear Coat Material")
                 .WithAlpha(AlphaMode.MASK, 0.6f)
                 .WithEmissive(tex1, new Vector3(0.2f, 0.3f, 0.1f))
                 .WithNormal(tex1, 0.3f)
-                .WithOcclusion(tex1, 0.4f)
-
-                .WithSpecularGlossinessShader()
-                    .WithDiffuse(tex1, new Vector4(0.7f, 0, 0f, 0.8f))
-                    .WithSpecularGlossiness(tex1, new Vector3(0.7f, 0, 0f), 0.8f);
-                
-            
-            Assert.IsTrue(MaterialBuilder.AreEqualByContent(srcMaterial, Schema2Roundtrip(srcMaterial)));
-            Assert.IsTrue(MaterialBuilder.AreEqualByContent(srcMaterial, srcMaterial.Clone()));
+                .WithOcclusion(tex1, 0.4f);
+
+            material.WithMetallicRoughnessShader()
+                .WithBaseColor(tex1, new Vector4(0.7f, 0, 0f, 0.8f))
+                .WithMetallicRoughness(tex1, 0.2f, 0.4f);
+
+            material.WithClearCoat(tex1, 1)
+                .WithClearCoatNormal(tex1)
+                .WithClearCoatRoughness(tex1, 1);
+
+            return material;
         }
 
-        [Test]
-        public void CreateSpecularGlossinessWithFallback()
+        [Obsolete("SpecularGlossiness has been deprecated by Khronos")]
+        private static MaterialBuilder _CreateSpecularGlossinessMaterialWithFallback()
         {
             var assetsPath = System.IO.Path.Combine(TestContext.CurrentContext.TestDirectory, "Assets");
             var tex1 = System.IO.Path.Combine(assetsPath, "shannon.webp");
@@ -173,15 +192,15 @@ namespace SharpGLTF.Materials
                 // fallback and primary material must have exactly the same properties
                 .WithDoubleSide(true)
                 .WithAlpha(AlphaMode.MASK, 0.75f)
-                .WithEmissive(tex1, new Vector3(0.2f, 0.3f, 0.1f))
+                .WithEmissive(tex1, new Vector3(0.2f, 0.3f, 0.1f), 4)
                 .WithNormal(tex1, 0.3f)
-                .WithOcclusion(tex1, 0.4f)
+                .WithOcclusion(tex1, 0.4f);
+
+            // primary must use Specular Glossiness shader.
+            primary.WithSpecularGlossinessShader()
+                .WithDiffuse(tex1, new Vector4(0.7f, 0, 0f, 1.0f))
+                .WithSpecularGlossiness(tex1, new Vector3(0.7f, 0, 0f), 0.8f);
 
-                // primary must use Specular Glossiness shader.
-                .WithSpecularGlossinessShader()
-                    .WithDiffuse(tex1, new Vector4(0.7f, 0, 0f, 1.0f))
-                    .WithSpecularGlossiness(tex1, new Vector3(0.7f, 0, 0f), 0.8f);
-            
             // set fallback textures for engines that don't support WEBP texture format
             primary.GetChannel(KnownChannel.Normal).Texture.FallbackImage = tex2;
             primary.GetChannel(KnownChannel.Emissive).Texture.FallbackImage = tex2;
@@ -193,12 +212,29 @@ namespace SharpGLTF.Materials
             primary.WithMetallicRoughnessFallback(tex1, new Vector4(0.7f, 0, 0, 1), String.Empty, 0.6f, 0.7f);
             primary.CompatibilityFallback.GetChannel(KnownChannel.BaseColor).Texture.FallbackImage = tex2;
 
-            // check
-            Assert.IsTrue(MaterialBuilder.AreEqualByContent(primary, Schema2Roundtrip(primary)));
-            Assert.IsTrue(MaterialBuilder.AreEqualByContent(primary, primary.Clone()));
+            return primary;
         }
 
-        private static MaterialBuilder Schema2Roundtrip(MaterialBuilder srcMaterial)
+        [Obsolete("SpecularGlossiness has been deprecated by Khronos")]
+        private static MaterialBuilder _CreateSpecularGlossinessMaterial()
+        {
+            var assetsPath = System.IO.Path.Combine(TestContext.CurrentContext.TestDirectory, "Assets");
+            var tex1 = System.IO.Path.Combine(assetsPath, "shannon.png");
+
+            var material = new MaterialBuilder()
+                .WithAlpha(AlphaMode.MASK, 0.6f)
+                .WithEmissive(tex1, new Vector3(0.2f, 0.3f, 0.1f))
+                .WithNormal(tex1, 0.3f)
+                .WithOcclusion(tex1, 0.4f);
+
+            material.WithSpecularGlossinessShader()
+                .WithDiffuse(tex1, new Vector4(0.7f, 0, 0f, 0.8f))
+                .WithSpecularGlossiness(tex1, new Vector3(0.7f, 0, 0f), 0.8f);
+
+            return material;
+        }        
+
+        private static MaterialBuilder _Schema2Roundtrip(MaterialBuilder srcMaterial)
         {
             // converts a MaterialBuilder to a Schema2.Material and back to a MaterialBuilder
 

+ 22 - 0
tests/SharpGLTF.Toolkit.Tests/Materials/MaterialTypesTests.cs

@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using NUnit.Framework;
+
+namespace SharpGLTF.Materials
+{
+    internal class MaterialTypesTests
+    {
+        [Test]
+        public void CheckKnownPropertyEnum()
+        {
+            var knownPropertyValues = Enum.GetNames(typeof(KnownProperty));
+            var schemaPropertyValues = Enum.GetNames(typeof(Schema2._MaterialParameterKey));            
+
+            CollectionAssert.AreEqual(schemaPropertyValues, knownPropertyValues);
+        }
+    }
+}