浏览代码

Added new material extensions to MaterialBuilder

vpenades 8 月之前
父节点
当前提交
3ec77194e0

+ 10 - 9
src/SharpGLTF.Core/Schema2/gltf.MaterialParameter.cs

@@ -45,14 +45,18 @@ namespace SharpGLTF.Schema2
         RGB,
         RGBA,
 
-        NormalScale,
-        OcclusionStrength,
-        EmissiveStrength,
-
         Minimum, Maximum,
 
+        NormalScale,
+
         IndexOfRefraction,
 
+        AnisotropyRotation,
+
+        OcclusionStrength,
+        EmissiveStrength,
+        AnisotropyStrength,
+
         MetallicFactor,
         RoughnessFactor,
         SpecularFactor,
@@ -61,11 +65,8 @@ namespace SharpGLTF.Schema2
         ThicknessFactor,
         TransmissionFactor,
         IridescenceFactor,
-        AttenuationDistance,
-        AnisotropyStrength,
-        AnisotropyRotation,
-        DiffuseTransmissionFactor,
-        DiffuseTransmissionColor,
+        AttenuationDistance,        
+        DiffuseTransmissionFactor,        
     }
 
     [System.Diagnostics.DebuggerDisplay("{_Key} = {Value}")]

+ 7 - 7
src/SharpGLTF.Core/Schema2/gltf.MaterialsFactory.cs

@@ -57,13 +57,13 @@ namespace SharpGLTF.Schema2
             foreach (var extn in extensionNames)
             {
                 if (extn == "Sheen") this.UseExtension<MaterialSheen>();
+                if (extn == "Volume") this.UseExtension<MaterialVolume>();
                 if (extn == "Specular") this.UseExtension<MaterialSpecular>();
-                if (extn == "ClearCoat") this.UseExtension<MaterialClearCoat>();
+                if (extn == "ClearCoat") this.UseExtension<MaterialClearCoat>();                
+                if (extn == "Anisotropy") this.UseExtension<MaterialAnisotropy>();
+                if (extn == "Iridescence") this.UseExtension<MaterialIridescence>();
                 if (extn == "Transmission") this.UseExtension<MaterialTransmission>();
                 if (extn == "DiffuseTransmission") this.UseExtension<MaterialDiffuseTransmission>();
-                if (extn == "Volume") this.UseExtension<MaterialVolume>();
-                if (extn == "Anisotropy") this.UseExtension<MaterialAnisotropy>();
-                if (extn == "Iridiscence") this.UseExtension<MaterialIridescence>();
             }
         }
 
@@ -670,10 +670,10 @@ namespace SharpGLTF.Schema2
 
         public IEnumerable<MaterialChannel> GetChannels(Material material)
         {
-            var iridisTexture = new _MaterialTexture(() => _iridescenceTexture, () => SetProperty(this, ref _iridescenceTexture, new TextureInfo()));
+            var iridesTexture = new _MaterialTexture(() => _iridescenceTexture, () => SetProperty(this, ref _iridescenceTexture, new TextureInfo()));
             var factor = new _MaterialParameter<float>(_MaterialParameterKey.IridescenceFactor, (float)_iridescenceFactorDefault, () => IridescenceFactor, v => IridescenceFactor = v);
             var idxRef = new _MaterialParameter<float>(_MaterialParameterKey.IndexOfRefraction, (float)_iridescenceIorDefault, () => IridescenceIndexOfRefraction, v => IridescenceIndexOfRefraction = v);
-            yield return new MaterialChannel(material, "Iridescence", iridisTexture, factor, idxRef);
+            yield return new MaterialChannel(material, "Iridescence", iridesTexture, factor, idxRef);
 
             var thicknessTexture = new _MaterialTexture(() => _iridescenceThicknessTexture, () => SetProperty(this, ref _iridescenceThicknessTexture, new TextureInfo()));
             var thkMin = new _MaterialParameter<float>(_MaterialParameterKey.Minimum, (float)_iridescenceThicknessMinimumDefault, () => IridescenceThicknessMinimum, v => IridescenceThicknessMinimum = v);
@@ -754,7 +754,7 @@ namespace SharpGLTF.Schema2
             yield return new MaterialChannel(material, "DiffuseTransmissionFactor", factorTexture, factorParameter);
 
             var colorTexture = new _MaterialTexture(() => _diffuseTransmissionColorTexture, () => SetProperty(this, ref _diffuseTransmissionColorTexture, new TextureInfo()));
-            var colorParameter = new _MaterialParameter<Vector3>(_MaterialParameterKey.DiffuseTransmissionColor, _diffuseTransmissionColorFactorDefault, () => DiffuseTransmissionColorFactor, v => DiffuseTransmissionColorFactor = v);            
+            var colorParameter = new _MaterialParameter<Vector3>(_MaterialParameterKey.RGB, _diffuseTransmissionColorFactorDefault, () => DiffuseTransmissionColorFactor, v => DiffuseTransmissionColorFactor = v);            
             yield return new MaterialChannel(material, "DiffuseTransmissionColor", colorTexture, colorParameter);
         }
     }

+ 70 - 50
src/SharpGLTF.Toolkit/Materials/MaterialBuilder.cs

@@ -1,10 +1,8 @@
 using System;
 using System.Collections.Generic;
-using System.Globalization;
 using System.Linq;
 using System.Numerics;
 using System.Runtime.CompilerServices;
-using System.Text;
 
 namespace SharpGLTF.Materials
 {
@@ -90,6 +88,7 @@ namespace SharpGLTF.Materials
         [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
         private string _ShaderStyle = SHADERPBRMETALLICROUGHNESS;
 
+
         public AlphaMode AlphaMode { get; set; } = AlphaMode.OPAQUE;
 
         public Single AlphaCutoff { get; set; } = 0.5f;
@@ -130,7 +129,8 @@ namespace SharpGLTF.Materials
             if (!BaseBuilder.AreEqualByContent(x, y)) return false;
 
             if (x.AlphaMode != y.AlphaMode) return false;
-            if (x.AlphaCutoff != y.AlphaCutoff) return false;
+            // AlphaCutoff only has meaning when AlphaMode = Mask
+            if (x.AlphaMode == AlphaMode.MASK && x.AlphaCutoff != y.AlphaCutoff) return false;
             if (x.DoubleSided != y.DoubleSided) return false;
             if (x.IndexOfRefraction != y.IndexOfRefraction) return false;
             if (x._ShaderStyle != y._ShaderStyle) return false;
@@ -218,24 +218,7 @@ namespace SharpGLTF.Materials
             }
         }
 
-        public ChannelBuilder GetChannel(KnownChannel channelKey)
-        {
-            return _Channels.FirstOrDefault(item => item.Key == channelKey);
-        }
-
-        public ChannelBuilder UseChannel(KnownChannel channelKey)
-        {
-            Guard.IsTrue(_GetValidChannels().Contains(channelKey), nameof(channelKey));
-
-            var ch = GetChannel(channelKey);
-            if (ch != null) return ch;
-
-            ch = new ChannelBuilder(this, channelKey);
-            _Channels.Add(ch);
-
-            return ch;
-        }
-
+        [Obsolete("Use GetChannel with KnownChannel whenever possible")]
         public ChannelBuilder GetChannel(string channelKey)
         {
             Guard.NotNullOrEmpty(channelKey, nameof(channelKey));
@@ -244,6 +227,7 @@ namespace SharpGLTF.Materials
             return GetChannel(key);
         }
 
+        [Obsolete("Use UseChannel with KnownChannel whenever possible")]
         public ChannelBuilder UseChannel(string channelKey)
         {
             Guard.NotNullOrEmpty(channelKey, nameof(channelKey));
@@ -252,6 +236,24 @@ namespace SharpGLTF.Materials
             return UseChannel(key);
         }
 
+        public ChannelBuilder GetChannel(KnownChannel channelKey)
+        {
+            return _Channels.FirstOrDefault(item => item.Key == channelKey);
+        }        
+
+        public ChannelBuilder UseChannel(KnownChannel channelKey)
+        {
+            Guard.IsTrue(_GetValidChannels().Contains(channelKey), nameof(channelKey));
+
+            var ch = GetChannel(channelKey);
+            if (ch != null) return ch;
+
+            ch = new ChannelBuilder(this, channelKey);
+            _Channels.Add(ch);
+
+            return ch;
+        }        
+
         public void RemoveChannel(KnownChannel key)
         {
             var idx = _Channels.IndexOf(item => item.Key == key);
@@ -261,11 +263,11 @@ namespace SharpGLTF.Materials
 
         internal void ValidateForSchema2()
         {
-            var hasClearCoat = this.GetChannel("ClearCoat") != null
-                || this.GetChannel("ClearCoatRoughness") != null
-                || this.GetChannel("ClearCoatNormal") != null;
+            var hasClearCoat = this.GetChannel(KnownChannel.ClearCoat) != null
+                || this.GetChannel(KnownChannel.ClearCoatNormal) != null
+                || this.GetChannel(KnownChannel.ClearCoatRoughness) != null;
 
-            var hasTransmission = this.GetChannel("Transmission") != null;
+            var hasTransmission = this.GetChannel(KnownChannel.Transmission) != null;
 
             if (this.ShaderStyle == SHADERPBRSPECULARGLOSSINESS)
             {
@@ -365,11 +367,21 @@ namespace SharpGLTF.Materials
             return this;
         }
 
+        [Obsolete("Use WithChannelImage(KnownChannel channelKey, ImageBuilder primaryImage)")]
+        public MaterialBuilder WithChannelImage(string channelKey, ImageBuilder primaryImage)
+        {
+            this.UseChannel(channelKey)
+                .UseTexture()
+                .WithPrimaryImage(primaryImage);
+
+            return this;
+        }
+
         public MaterialBuilder WithChannelParam(KnownChannel channelKey, KnownProperty propertyName, Object parameter)
         {
             this.UseChannel(channelKey).Parameters[propertyName] = MaterialValue.CreateFrom(parameter);
             return this;
-        }
+        }        
 
         public MaterialBuilder WithChannelImage(KnownChannel channelKey, ImageBuilder primaryImage)
         {
@@ -386,14 +398,7 @@ namespace SharpGLTF.Materials
             return this;
         }
 
-        public MaterialBuilder WithChannelImage(string channelKey, ImageBuilder primaryImage)
-        {
-            this.UseChannel(channelKey)
-                .UseTexture()
-                .WithPrimaryImage(primaryImage);
-
-            return this;
-        }
+        
 
         /// <summary>
         /// Defines a fallback <see cref="MaterialBuilder"/> instance for the current <see cref="MaterialBuilder"/>.
@@ -490,61 +495,68 @@ namespace SharpGLTF.Materials
 
         public MaterialBuilder WithClearCoat(ImageBuilder imageFile, float intensity)
         {
-            WithChannelImage(KnownChannel.ClearCoat, imageFile);
-            // WithChannelParam(KnownChannel.ClearCoat, new Vector4(intensity, 0, 0, 0));
+            WithChannelImage(KnownChannel.ClearCoat, imageFile);            
             WithChannelParam(KnownChannel.ClearCoat, KnownProperty.ClearCoatFactor, intensity);
             return this;
         }
 
         public MaterialBuilder WithClearCoatRoughness(ImageBuilder imageFile, float roughness)
         {
-            WithChannelImage(KnownChannel.ClearCoatRoughness, imageFile);
-            // WithChannelParam(KnownChannel.ClearCoatRoughness, new Vector4(roughness, 0, 0, 0));
+            WithChannelImage(KnownChannel.ClearCoatRoughness, imageFile);            
             WithChannelParam(KnownChannel.ClearCoatRoughness, KnownProperty.RoughnessFactor, roughness);
             return this;
         }
 
         public MaterialBuilder WithTransmission(ImageBuilder imageFile, float intensity)
         {
-            WithChannelImage(KnownChannel.Transmission, imageFile);
-            // WithChannelParam(KnownChannel.Transmission, new Vector4(intensity, 0, 0, 0));
+            WithChannelImage(KnownChannel.Transmission, imageFile);            
             WithChannelParam(KnownChannel.Transmission, KnownProperty.TransmissionFactor, intensity);
             return this;
         }
 
+        public MaterialBuilder WithDiffuseTransmissionFactor(ImageBuilder imageFile, float factor)
+        {
+            WithChannelImage(KnownChannel.DiffuseTransmissionFactor, imageFile);
+            WithChannelParam(KnownChannel.DiffuseTransmissionFactor, KnownProperty.DiffuseTransmissionFactor, factor);
+            return this;
+        }
+
+        public MaterialBuilder WithDiffuseTransmissionColor(ImageBuilder imageFile, Vector3? rgb = null)
+        {
+            WithChannelImage(KnownChannel.DiffuseTransmissionColor, imageFile);
+            if (rgb.HasValue) WithChannelParam(KnownChannel.DiffuseTransmissionColor, KnownProperty.RGB, rgb.Value);
+            return this;
+        }
+
         public MaterialBuilder WithSpecularColor(ImageBuilder imageFile, Vector3? rgb = null)
         {
-            WithChannelImage(KnownChannel.SpecularColor, imageFile);
-            // if (rgb.HasValue) WithChannelParam(KnownChannel.SpecularColor, new Vector4(rgb.Value, 0));
+            WithChannelImage(KnownChannel.SpecularColor, imageFile);            
             if (rgb.HasValue) WithChannelParam(KnownChannel.SpecularColor, KnownProperty.RGB, rgb.Value);
             return this;
         }
 
         public MaterialBuilder WithSpecularFactor(ImageBuilder imageFile, float factor)
         {
-            WithChannelImage(KnownChannel.SpecularFactor, imageFile);
-            // WithChannelParam(KnownChannel.SpecularFactor, new Vector4(factor, 0, 0, 0));
+            WithChannelImage(KnownChannel.SpecularFactor, imageFile);            
             WithChannelParam(KnownChannel.SpecularFactor, KnownProperty.SpecularFactor, factor);
             return this;
         }
 
         public MaterialBuilder WithVolumeThickness(ImageBuilder imageFile, float factor)
         {
-            WithChannelImage(KnownChannel.VolumeThickness, imageFile);
-            // WithChannelParam(KnownChannel.VolumeThickness, new Vector4(factor, 0, 0, 0));
+            WithChannelImage(KnownChannel.VolumeThickness, imageFile);            
             WithChannelParam(KnownChannel.VolumeThickness, KnownProperty.ThicknessFactor, factor);
             return this;
         }
 
         public MaterialBuilder WithVolumeAttenuation(Vector3 color, float distance)
-        {
-            // WithChannelParam(KnownChannel.VolumeAttenuation, new Vector4(color, distance));
+        {            
             WithChannelParam(KnownChannel.VolumeAttenuation, KnownProperty.RGB, color);
             WithChannelParam(KnownChannel.VolumeAttenuation, KnownProperty.AttenuationDistance, distance);
             return this;
         }
 
-        public MaterialBuilder WithIridiscence(ImageBuilder imageFile, float factor = 0f, float ior = 1.3f)
+        public MaterialBuilder WithIridescence(ImageBuilder imageFile, float factor = 0f, float ior = 1.3f)
         {
             WithChannelImage(KnownChannel.Iridescence, imageFile);            
             WithChannelParam(KnownChannel.Iridescence, KnownProperty.IridescenceFactor, factor);
@@ -552,7 +564,7 @@ namespace SharpGLTF.Materials
             return this;
         }
 
-        public MaterialBuilder WithIridiscenceThickness(ImageBuilder imageFile, float min = 100f, float max = 400f)
+        public MaterialBuilder WithIridescenceThickness(ImageBuilder imageFile, float min = 100f, float max = 400f)
         {
             WithChannelImage(KnownChannel.IridescenceThickness, imageFile);
             WithChannelParam(KnownChannel.IridescenceThickness, KnownProperty.Minimum, min);
@@ -560,6 +572,14 @@ namespace SharpGLTF.Materials
             return this;
         }
 
+        public MaterialBuilder WithAnisotropy(ImageBuilder imageFile, float strength = 0f, float rotation = 0f)
+        {
+            WithChannelImage(KnownChannel.Anisotropy, imageFile);
+            WithChannelParam(KnownChannel.Anisotropy, KnownProperty.AnisotropyStrength, strength);
+            WithChannelParam(KnownChannel.Anisotropy, KnownProperty.AnisotropyRotation, rotation);
+            return this;
+        }
+
         #endregion
 
         #region API - OBSOLETE

+ 34 - 5
src/SharpGLTF.Toolkit/Materials/MaterialEnums.cs

@@ -48,6 +48,11 @@ namespace SharpGLTF.Materials
 
         Iridescence,
         IridescenceThickness,
+
+        Anisotropy,
+
+        DiffuseTransmissionColor,
+        DiffuseTransmissionFactor
     }
 
     /// <summary>
@@ -63,12 +68,13 @@ namespace SharpGLTF.Materials
         RGB,
         RGBA,
 
+        Minimum, Maximum,
+
         NormalScale,
+
         OcclusionStrength,
         EmissiveStrength,
 
-        Minimum, Maximum,
-
         IndexOfRefraction,
 
         MetallicFactor,
@@ -80,10 +86,11 @@ namespace SharpGLTF.Materials
         TransmissionFactor,
         IridescenceFactor,
         AttenuationDistance,
+        DiffuseTransmissionFactor,
+
         AnisotropyStrength,
+
         AnisotropyRotation,
-        DiffuseTransmissionFactor,
-        DiffuseTransmissionColor,
     }
 
     partial class MaterialBuilder
@@ -127,7 +134,12 @@ namespace SharpGLTF.Materials
             KnownChannel.SpecularColor,
             KnownChannel.SpecularFactor,
             KnownChannel.VolumeThickness,
-            KnownChannel.VolumeAttenuation
+            KnownChannel.VolumeAttenuation,
+            KnownChannel.Iridescence,
+            KnownChannel.IridescenceThickness,
+            KnownChannel.Anisotropy,
+            KnownChannel.DiffuseTransmissionColor,
+            KnownChannel.DiffuseTransmissionFactor
         };
 
         [Obsolete("Deprecated by Khronos")]
@@ -196,6 +208,23 @@ namespace SharpGLTF.Materials
                     yield return new _Property(KnownProperty.AttenuationDistance, float.PositiveInfinity);
                     break;
 
+                case KnownChannel.Iridescence:
+                    yield return new _Property(KnownProperty.IridescenceFactor, 0f);
+                    yield return new _Property(KnownProperty.IndexOfRefraction, 1.3f);
+                    break;
+                case KnownChannel.IridescenceThickness:
+                    yield return new _Property(KnownProperty.Minimum, 100);
+                    yield return new _Property(KnownProperty.Maximum, 400);
+                    break;
+
+                case KnownChannel.Anisotropy:
+                    yield return new _Property(KnownProperty.AnisotropyStrength, 0f);
+                    yield return new _Property(KnownProperty.AnisotropyRotation, 0f);
+                    break;
+
+                case KnownChannel.DiffuseTransmissionFactor: yield return new _Property(KnownProperty.DiffuseTransmissionFactor, 20); break;
+                case KnownChannel.DiffuseTransmissionColor: yield return new _Property(KnownProperty.RGB, Vector3.One); break;                    
+
                 default: throw new NotImplementedException();
             }
         }

+ 60 - 34
src/SharpGLTF.Toolkit/Schema2/MaterialExtensions.cs

@@ -323,12 +323,14 @@ namespace SharpGLTF.Schema2
 
             foreach (var k in channelKeys)
             {
+                if (!Enum.TryParse<KnownChannel>(k, true, out var knownChannel)) continue;
+
                 var src = srcMaterial.FindChannel(k);
-                if (!src.HasValue) continue;
+                if (!src.HasValue) continue;                
 
-                if (src.Value.HasDefaultContent) continue;
+                if (src.Value.HasDefaultContent) continue;                
 
-                var dst = dstMaterial.UseChannel(k);
+                var dst = dstMaterial.UseChannel(knownChannel);
 
                 src.Value.CopyTo(dst);
             }
@@ -388,49 +390,62 @@ namespace SharpGLTF.Schema2
             srcMaterial.TryCopyNameAndExtrasTo(dstMaterial);
 
             dstMaterial.Alpha = srcMaterial.AlphaMode.ToSchema2();
-            dstMaterial.AlphaCutoff = srcMaterial.AlphaCutoff;
-            dstMaterial.DoubleSided = srcMaterial.DoubleSided;
-            
+            dstMaterial.AlphaCutoff = dstMaterial.Alpha == ALPHAMODEGLTF2.MASK ? srcMaterial.AlphaCutoff : 0.5f;
+            dstMaterial.DoubleSided = srcMaterial.DoubleSided;            
 
             var hasClearCoat
-                = srcMaterial.GetChannel("ClearCoat") != null
-                || srcMaterial.GetChannel("ClearCoatRoughness") != null
-                || srcMaterial.GetChannel("ClearCoatNormal") != null;
-
-            var hasTransmission = srcMaterial.GetChannel("Transmission") != null;
+                =  srcMaterial.GetChannel(KnownChannel.ClearCoat) != null
+                || srcMaterial.GetChannel(KnownChannel.ClearCoatNormal) != null
+                || srcMaterial.GetChannel(KnownChannel.ClearCoatRoughness) != null;            
 
             var hasSheen
-                = srcMaterial.GetChannel("SheenColor") != null
-                || srcMaterial.GetChannel("SheenRoughness") != null;
+                =  srcMaterial.GetChannel(KnownChannel.SheenColor) != null
+                || srcMaterial.GetChannel(KnownChannel.SheenRoughness) != null;
 
             var hasSpecular
-                = srcMaterial.GetChannel("SpecularColor") != null
-                || srcMaterial.GetChannel("SpecularFactor") != null;
+                =  srcMaterial.GetChannel(KnownChannel.SpecularColor) != null
+                || srcMaterial.GetChannel(KnownChannel.SpecularFactor) != null;
 
             var hasVolume
-                = srcMaterial.GetChannel("VolumeThickness") != null
-                || srcMaterial.GetChannel("VolumeAttenuation") != null;
+                =  srcMaterial.GetChannel(KnownChannel.VolumeThickness) != null
+                || srcMaterial.GetChannel(KnownChannel.VolumeAttenuation) != null;
 
-            srcMaterial.CopyChannelsTo(dstMaterial, "Normal", "Occlusion", "Emissive");
+            var hasIridescence
+                =  srcMaterial.GetChannel(KnownChannel.Iridescence) != null
+                || srcMaterial.GetChannel(KnownChannel.IridescenceThickness) != null;
+
+            var hasAnisotropy = srcMaterial.GetChannel(KnownChannel.Anisotropy) != null;
+
+            var hasTransmission = srcMaterial.GetChannel(KnownChannel.Transmission) != null;
+
+            var hasDiffuseTransmission
+                =  srcMaterial.GetChannel(KnownChannel.DiffuseTransmissionColor) != null
+                || srcMaterial.GetChannel(KnownChannel.DiffuseTransmissionFactor) != null;
+            
+            srcMaterial.CopyChannelsTo(dstMaterial, KnownChannel.Normal, KnownChannel.Occlusion, KnownChannel.Emissive);
 
             MaterialBuilder defMaterial = null;
 
             if (srcMaterial.ShaderStyle == "Unlit")
             {
                 dstMaterial.InitializeUnlit();
-                srcMaterial.CopyChannelsTo(dstMaterial, "BaseColor");
+                srcMaterial.CopyChannelsTo(dstMaterial, KnownChannel.BaseColor);
                 return;
             }
 
             if (srcMaterial.ShaderStyle == "PBRMetallicRoughness")
             {
                 dstMaterial.InitializePBRMetallicRoughness
-                    (
+                    (                    
+                    hasSheen ? "Sheen" : null,                    
+                    hasVolume ? "Volume" : null,
+                    hasSpecular ? "Specular" : null,
                     hasClearCoat ? "ClearCoat" : null,
+                    hasAnisotropy ? "Anisotropy" : null,
+                    hasIridescence ? "Iridescence" : null,                    
                     hasTransmission ? "Transmission" : null,
-                    hasSheen ? "Sheen" : null,
-                    hasSpecular ? "Specular" : null,
-                    hasVolume ? "Volume" : null);
+                    hasDiffuseTransmission ? "DiffuseTransmission" : null
+                    );
 
                 defMaterial = srcMaterial;
             }
@@ -438,7 +453,7 @@ namespace SharpGLTF.Schema2
             if (srcMaterial.ShaderStyle == "PBRSpecularGlossiness")
             {
                 dstMaterial.InitializePBRSpecularGlossiness(srcMaterial.CompatibilityFallback != null);
-                srcMaterial.CopyChannelsTo(dstMaterial, "Diffuse", "SpecularGlossiness");
+                srcMaterial.CopyChannelsTo(dstMaterial, KnownChannel.Diffuse, KnownChannel.SpecularGlossiness);
                 defMaterial = srcMaterial.CompatibilityFallback;
             }
 
@@ -449,12 +464,15 @@ namespace SharpGLTF.Schema2
             if (defMaterial != null)
             {
                 if (defMaterial.ShaderStyle != "PBRMetallicRoughness") throw new ArgumentException(nameof(srcMaterial.CompatibilityFallback.ShaderStyle));
-                defMaterial.CopyChannelsTo(dstMaterial, "BaseColor", "MetallicRoughness");
-                defMaterial.CopyChannelsTo(dstMaterial, "ClearCoat", "ClearCoatRoughness", "ClearCoatNormal");
-                defMaterial.CopyChannelsTo(dstMaterial, "Transmission");
-                defMaterial.CopyChannelsTo(dstMaterial, "SheenColor", "SheenRoughness");
-                defMaterial.CopyChannelsTo(dstMaterial, "SpecularColor", "SpecularFactor");
-                defMaterial.CopyChannelsTo(dstMaterial, "VolumeThickness", "VolumeAttenuation");
+                defMaterial.CopyChannelsTo(dstMaterial, KnownChannel.BaseColor, KnownChannel.MetallicRoughness);
+                defMaterial.CopyChannelsTo(dstMaterial, KnownChannel.ClearCoat, KnownChannel.ClearCoatNormal, KnownChannel.ClearCoatRoughness);
+                defMaterial.CopyChannelsTo(dstMaterial, KnownChannel.Transmission);
+                defMaterial.CopyChannelsTo(dstMaterial, KnownChannel.SheenColor, KnownChannel.SheenRoughness);
+                defMaterial.CopyChannelsTo(dstMaterial, KnownChannel.SpecularColor, KnownChannel.SpecularFactor);
+                defMaterial.CopyChannelsTo(dstMaterial, KnownChannel.VolumeThickness, KnownChannel.VolumeAttenuation);
+                defMaterial.CopyChannelsTo(dstMaterial, KnownChannel.Iridescence, KnownChannel.IridescenceThickness);
+                defMaterial.CopyChannelsTo(dstMaterial, KnownChannel.Anisotropy);
+                defMaterial.CopyChannelsTo(dstMaterial, KnownChannel.DiffuseTransmissionColor, KnownChannel.DiffuseTransmissionFactor);
             }
 
             // final validation
@@ -462,18 +480,25 @@ namespace SharpGLTF.Schema2
             System.Diagnostics.Debug.Assert(dstMaterial.IndexOfRefraction == srcMaterial.IndexOfRefraction, "set IOR after dst material initialization");            
         }
 
-        public static void CopyChannelsTo(this MaterialBuilder srcMaterial, Material dstMaterial, params string[] channelKeys)
+        [Obsolete]
+        public static void CopyChannelsTo(this MaterialBuilder srcMaterial, Material dstMaterial, params string[] channels)
+        {
+            var channelKeys = channels.Select(key => Enum.TryParse<KnownChannel>(key, out var val) ? val : default).ToArray();
+            CopyChannelsTo(srcMaterial, dstMaterial, channelKeys);
+        }
+
+        public static void CopyChannelsTo(this MaterialBuilder srcMaterial, Material dstMaterial, params KnownChannel[] channels)
         {
             Guard.NotNull(srcMaterial, nameof(srcMaterial));
             Guard.NotNull(dstMaterial, nameof(dstMaterial));
-            Guard.NotNull(channelKeys, nameof(channelKeys));
+            Guard.NotNull(channels, nameof(channels));
 
-            foreach (var k in channelKeys)
+            foreach (var k in channels)
             {
                 var src = srcMaterial.GetChannel(k);
                 if (src == null) continue;
 
-                var dst = dstMaterial.FindChannel(k);
+                var dst = dstMaterial.FindChannel(k.ToString());
                 if (dst == null) continue;
 
                 src.CopyTo(dst.Value);
@@ -589,3 +614,4 @@ namespace SharpGLTF.Schema2
         #endregion
     }
 }
+

+ 123 - 117
tests/SharpGLTF.Toolkit.Tests/Materials/MaterialBuilderTests.cs

@@ -44,7 +44,7 @@ namespace SharpGLTF.Materials
             bag.Add(clnMaterial);
 
             Assert.That(bag, Has.Count.EqualTo(2));
-        }
+        }        
 
         [Test]
         public void CreateUnlit()
@@ -53,64 +53,6 @@ namespace SharpGLTF.Materials
 
             Assert.That(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
             Assert.That(MaterialBuilder.AreEqualByContent(material, material.Clone()));
-        }        
-
-        [Test]
-        public void CreateMetallicRoughness()
-        {
-            var material = _CreateMetallicRoughnessMaterial();
-
-            Assert.That(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
-            Assert.That(MaterialBuilder.AreEqualByContent(material, material.Clone()));
-        }        
-
-        [Test]
-        public void CreateClearCoat()
-        {
-            var material = _CreateClearCoatMaterial();
-
-            Assert.That(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
-            Assert.That(MaterialBuilder.AreEqualByContent(material, material.Clone()));
-        }        
-
-        [Test]
-        public void CreateVolume()
-        {
-            var material = _CreateVolumeMaterial();
-
-            Assert.That(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
-            Assert.That(MaterialBuilder.AreEqualByContent(material, material.Clone()));
-        }        
-
-        [Test]
-        public void CreateSpecularGlossiness()
-        {
-            var material = _CreateSpecularGlossinessMaterial();
-
-            Assert.That(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
-            Assert.That(MaterialBuilder.AreEqualByContent(material, material.Clone()));
-        }        
-
-        [Test]
-        public void CreateSpecularGlossinessWithFallback()
-        {
-            var material = _CreateSpecularGlossinessMaterialWithFallback();
-
-            // check
-            Assert.That(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)), Is.True);
-            Assert.That(MaterialBuilder.AreEqualByContent(material, material.Clone()), Is.True);
-        }
-
-        [Test]
-        public void CreateIORWithFallback()
-        {
-            // https://github.com/vpenades/SharpGLTF/issues/246
-
-            var material = new MaterialBuilder("MaterialWithIOR");
-            material.IndexOfRefraction = 7;
-
-            Assert.That(MaterialBuilder.AreEqualByContent(material, material.Clone()), Is.True);
-            Assert.That(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)), Is.True);            
         }
 
         private static MaterialBuilder _CreateUnlitMaterial()
@@ -127,12 +69,21 @@ namespace SharpGLTF.Materials
             return material;
         }
 
+        [Test]
+        public void CreateMetallicRoughness()
+        {
+            var material = _CreateMetallicRoughnessMaterial();
+
+            Assert.That(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
+            Assert.That(MaterialBuilder.AreEqualByContent(material, material.Clone()));
+        }        
+
         private static MaterialBuilder _CreateMetallicRoughnessMaterial()
         {
             var tex1 = ResourceInfo.From("shannon.png").FilePath;
 
             var material = new MaterialBuilder("Metallic Roughness Material")
-                .WithAlpha(AlphaMode.MASK, 0.6f)
+                .WithAlpha(AlphaMode.MASK, 0.6f) // Note: this is just an example, for a default opaque material, use WithAlpha(AlphaMode.OPAQUE, 0.5)
                 .WithEmissive(tex1, new Vector3(0.2f, 0.3f, 0.1f), 6)
                 .WithNormal(tex1, 0.3f)
                 .WithOcclusion(tex1, 0.4f);
@@ -151,66 +102,139 @@ namespace SharpGLTF.Materials
             return material;
         }
 
-        private static MaterialBuilder _CreateVolumeMaterial()
+        [Test]
+        public void CreateMaterialWithExtensions()
         {
-            var tex1 = ResourceInfo.From("shannon.png").FilePath;
+            var material = _CreateMetallicRoughnessMaterial();
 
-            var material = new MaterialBuilder("Volume Material")
-                .WithAlpha(AlphaMode.MASK, 0.6f);
+            // https://github.com/vpenades/SharpGLTF/issues/246
+            material.IndexOfRefraction = 7;
 
-            material.WithMetallicRoughnessShader()
-                .WithBaseColor(tex1, new Vector4(0.7f, 0, 0f, 0.8f))
-                .WithMetallicRoughness(tex1, 0.2f, 0.4f);
+            Assert.That(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
+            Assert.That(MaterialBuilder.AreEqualByContent(material, material.Clone()));
 
-            material.WithVolumeAttenuation(Vector3.One * 0.3f, 0.6f)
-                .WithVolumeThickness(tex1, 0.4f);
+            _AddClearCoat(material);
 
-            return material;
+            Assert.That(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
+            Assert.That(MaterialBuilder.AreEqualByContent(material, material.Clone()));
+
+            _AddVolume(material);
+
+            Assert.That(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
+            Assert.That(MaterialBuilder.AreEqualByContent(material, material.Clone()));                        
+
+            _AddIridescence(material);
+
+            Assert.That(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
+            Assert.That(MaterialBuilder.AreEqualByContent(material, material.Clone()));
+
+            _AddAnisotropy(material);
+
+            Assert.That(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
+            Assert.That(MaterialBuilder.AreEqualByContent(material, material.Clone()));
+
+            _AddTransmission(material);
+
+            Assert.That(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
+            Assert.That(MaterialBuilder.AreEqualByContent(material, material.Clone()));
+
+            _AddDiffuseTransmission(material);
+
+            Assert.That(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
+            Assert.That(MaterialBuilder.AreEqualByContent(material, material.Clone()));
         }
 
-        private static MaterialBuilder _CreateIridescenceMaterial()
+        private static void _AddVolume(MaterialBuilder material)
         {
-            var tex1 = ResourceInfo.From("shannon.png").FilePath;
+            var tex1 = ResourceInfo.From("shannon.png").FilePath;            
 
-            var material = new MaterialBuilder("Volume Material")
-                .WithAlpha(AlphaMode.OPAQUE);
+            material.WithVolumeAttenuation(Vector3.One * 0.3f, 0.6f)
+                .WithVolumeThickness(tex1, 0.4f);            
+        }        
 
-            material.WithMetallicRoughnessShader()
-                .WithBaseColor(tex1, new Vector4(0.7f, 0, 0f, 0.8f))
-                .WithMetallicRoughness(tex1, 0.2f, 0.4f);
+        private static void _AddClearCoat(MaterialBuilder material)
+        {            
+            var tex1 = ResourceInfo.From("shannon.png").FilePath;            
 
-            material
-                .WithIridiscence(default, 0, 1.3f)
-                .WithIridiscenceThickness(default, 100, 400);
+            material.WithClearCoat(tex1, 0.9f)
+                .WithClearCoatNormal(tex1)
+                .WithClearCoatRoughness(tex1, 0.9f);
+        }       
 
-            return material;
+        private static void _AddIridescence(MaterialBuilder material)
+        {
+            material
+                .WithIridescence(default, 0.2f, 1.5f)
+                .WithIridescenceThickness(default, 120, 330);
         }
 
-        private static MaterialBuilder _CreateClearCoatMaterial()
-        {            
+        private static void _AddAnisotropy(MaterialBuilder material)
+        {
             var tex1 = ResourceInfo.From("shannon.png").FilePath;
 
-            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);
+            material.WithAnisotropy(tex1, 0.2f, 3f);
+        }
 
-            material.WithMetallicRoughnessShader()
-                .WithBaseColor(tex1, new Vector4(0.7f, 0, 0f, 0.8f))
-                .WithMetallicRoughness(tex1, 0.2f, 0.4f);
+        private static void _AddTransmission(MaterialBuilder material)
+        {
+            var tex1 = ResourceInfo.From("shannon.png").FilePath;
 
-            material.WithClearCoat(tex1, 1)
-                .WithClearCoatNormal(tex1)
-                .WithClearCoatRoughness(tex1, 1);
+            material.WithTransmission(tex1, 0.9f);
+        }
 
-            return material;
+        private static void _AddDiffuseTransmission(MaterialBuilder material)
+        {
+            var tex1 = ResourceInfo.From("shannon.png").FilePath;
+
+            material.WithDiffuseTransmissionFactor(tex1, 0.9f);
+            material.WithDiffuseTransmissionColor(tex1, Vector3.One * 0.2f);
         }        
 
+        private static MaterialBuilder _Schema2Roundtrip(MaterialBuilder srcMaterial)
+        {
+            // converts a MaterialBuilder to a Schema2.Material and back to a MaterialBuilder
+
+            var dstModel = Schema2.ModelRoot.CreateModel();
+            var dstMaterial = dstModel.CreateMaterial(srcMaterial.Name);
+
+            srcMaterial.CopyTo(dstMaterial); // copy MaterialBuilder to Schema2.Material.
+
+            var ctx = new ValidationResult(dstModel,ValidationMode.Strict, true);
+            dstModel.ValidateReferences(ctx.GetContext());
+            dstModel.ValidateContent(ctx.GetContext());
+
+            var rtpMaterial = new MaterialBuilder(dstMaterial.Name);
+
+            dstMaterial.CopyTo(rtpMaterial);// copy Schema2.Material to MaterialBuilder.
+
+            return rtpMaterial;
+        }
+
+        #region obsolete (kept for backwards compatibility)
+
+        [Test]
+        public void CreateSpecularGlossiness()
+        {
+            var material = _CreateSpecularGlossinessMaterial();
+
+            Assert.That(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)));
+            Assert.That(MaterialBuilder.AreEqualByContent(material, material.Clone()));
+        }
+
+        [Test]
+        public void CreateSpecularGlossinessWithFallback()
+        {
+            var material = _CreateSpecularGlossinessMaterialWithFallback();
+
+            // check
+            Assert.That(MaterialBuilder.AreEqualByContent(material, _Schema2Roundtrip(material)), Is.True);
+            Assert.That(MaterialBuilder.AreEqualByContent(material, material.Clone()), Is.True);
+        }
+
         [Obsolete("SpecularGlossiness has been deprecated by Khronos")]
         private static MaterialBuilder _CreateSpecularGlossinessMaterialWithFallback()
         {
-            
+
             var tex1 = ResourceInfo.From("shannon.webp").FilePath;
             var tex2 = ResourceInfo.From("shannon.png").FilePath;
 
@@ -245,7 +269,7 @@ namespace SharpGLTF.Materials
         [Obsolete("SpecularGlossiness has been deprecated by Khronos")]
         private static MaterialBuilder _CreateSpecularGlossinessMaterial()
         {
-            
+
             var tex1 = ResourceInfo.From("shannon.png").FilePath;
 
             var material = new MaterialBuilder()
@@ -259,26 +283,8 @@ namespace SharpGLTF.Materials
                 .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
-
-            var dstModel = Schema2.ModelRoot.CreateModel();
-            var dstMaterial = dstModel.CreateMaterial(srcMaterial.Name);
-
-            srcMaterial.CopyTo(dstMaterial); // copy MaterialBuilder to Schema2.Material.
-
-            var ctx = new ValidationResult(dstModel,ValidationMode.Strict, true);
-            dstModel.ValidateReferences(ctx.GetContext());
-            dstModel.ValidateContent(ctx.GetContext());
-
-            var rtpMaterial = new MaterialBuilder(dstMaterial.Name);
-
-            dstMaterial.CopyTo(rtpMaterial);// copy Schema2.Material to MaterialBuilder.
-
-            return rtpMaterial;
         }
+
+        #endregion
     }
 }