Browse Source

More null guards, docs and small code fixes.
Added more methods and properties to MaterialChannel to replace obsolete vector4 Parameter

Vicente Penades 3 years ago
parent
commit
059a9476ff

+ 3 - 0
.editorconfig

@@ -53,6 +53,9 @@ dotnet_diagnostic.CA2225.severity = silent
 
 
 # CA1707: Identifiers should not contain underscores
 # CA1707: Identifiers should not contain underscores
 dotnet_diagnostic.CA1707.severity = silent
 dotnet_diagnostic.CA1707.severity = silent
+
+# CA1815: Override equals and operator equals on value types
+dotnet_diagnostic.CA1815.severity = silent
 
 
 [*.{cs,vb}]
 [*.{cs,vb}]
 #### Naming styles ####
 #### Naming styles ####

+ 4 - 4
examples/SharpGLTF.Runtime.MonoGame/LoaderContext.BasicEffect.cs

@@ -147,8 +147,8 @@ namespace SharpGLTF.Runtime
             if (mr == null) return Vector3.One; // default value 16
             if (mr == null) return Vector3.One; // default value 16
 
 
             var diffuse = GetDiffuseColor(srcMaterial);
             var diffuse = GetDiffuseColor(srcMaterial);
-            var metallic = mr.Value.Parameter.X;
-            var roughness = mr.Value.Parameter.Y;
+            var metallic = mr.Value.GetFactor("MetallicFactor");
+            var roughness = mr.Value.GetFactor("RoughnessFactor");
 
 
             var k = Vector3.Zero;
             var k = Vector3.Zero;
             k += Vector3.Lerp(diffuse, Vector3.Zero, roughness);
             k += Vector3.Lerp(diffuse, Vector3.Zero, roughness);
@@ -164,8 +164,8 @@ namespace SharpGLTF.Runtime
 
 
             if (mr == null) return 16; // default value = 16
             if (mr == null) return 16; // default value = 16
 
 
-            var metallic = mr.Value.Parameter.X;
-            var roughness = mr.Value.Parameter.Y;
+            var metallic = mr.Value.GetFactor("MetallicFactor");
+            var roughness = mr.Value.GetFactor("RoughnessFactor");
 
 
             return 4 + 16 * metallic;
             return 4 + 16 * metallic;
         }
         }

+ 2 - 2
src/Shared/Guard.cs

@@ -16,7 +16,7 @@ namespace SharpGLTF
 
 
         public static void NotNullOrEmpty(string target, string parameterName, string message = "")
         public static void NotNullOrEmpty(string target, string parameterName, string message = "")
         {
         {
-            NotNull(target, parameterName, message);
+            if (target == null) throw new ArgumentNullException(parameterName, message);
 
 
             if (!string.IsNullOrWhiteSpace(target)) return;
             if (!string.IsNullOrWhiteSpace(target)) return;
 
 
@@ -94,7 +94,7 @@ namespace SharpGLTF
 
 
         public static void NotNullOrEmpty<T>(IEnumerable<T> target, string parameterName, string message = "")
         public static void NotNullOrEmpty<T>(IEnumerable<T> target, string parameterName, string message = "")
         {
         {
-            NotNull(target, parameterName, message);
+            if (target == null) throw new ArgumentNullException(parameterName, message);
 
 
             if (target.Any()) return;
             if (target.Any()) return;
 
 

+ 1 - 1
src/SharpGLTF.Core/Animations/CurveSamplers.Cubic.cs

@@ -83,7 +83,7 @@ namespace SharpGLTF.Animations
         public ICurveSampler<T> ToFastSampler()
         public ICurveSampler<T> ToFastSampler()
         {
         {
             var traits = _Traits;
             var traits = _Traits;
-            return FastCurveSampler<T>.CreateFrom(_Sequence, chunk => new CubicSampler<T>(chunk, traits)) ?? this;
+            return FastCurveSampler<T>.CreateFrom(_Sequence, chunk => new CubicSampler<T>(chunk, traits));
         }
         }
 
 
         #endregion
         #endregion

+ 1 - 1
src/SharpGLTF.Core/Animations/CurveSamplers.Linear.cs

@@ -67,7 +67,7 @@ namespace SharpGLTF.Animations
         public ICurveSampler<T> ToFastSampler()
         public ICurveSampler<T> ToFastSampler()
         {
         {
             var traits = _Traits;
             var traits = _Traits;
-            return FastCurveSampler<T>.CreateFrom(_Sequence, chunk => new LinearSampler<T>(chunk, traits)) ?? this;
+            return FastCurveSampler<T>.CreateFrom(_Sequence, chunk => new LinearSampler<T>(chunk, traits));
         }
         }
 
 
         #endregion
         #endregion

+ 1 - 1
src/SharpGLTF.Core/Animations/CurveSamplers.Step.cs

@@ -68,7 +68,7 @@ namespace SharpGLTF.Animations
         public ICurveSampler<T> ToFastSampler()
         public ICurveSampler<T> ToFastSampler()
         {
         {
             var traits = _Traits;
             var traits = _Traits;
-            return FastCurveSampler<T>.CreateFrom(_Sequence, chunk => new StepSampler<T>(chunk, traits)) ?? this;
+            return FastCurveSampler<T>.CreateFrom(_Sequence, chunk => new StepSampler<T>(chunk, traits));
         }
         }
 
 
         #endregion
         #endregion

+ 4 - 0
src/SharpGLTF.Core/IO/JsonContent.cs

@@ -196,6 +196,8 @@ namespace SharpGLTF.IO
 
 
         public JsonContent GetNode(params IConvertible[] path)
         public JsonContent GetNode(params IConvertible[] path)
         {
         {
+            Guard.NotNull(path, nameof(path));
+
             var value = _JsonStaticUtils.GetNode(this._Content, path);
             var value = _JsonStaticUtils.GetNode(this._Content, path);
             return new JsonContent(value);
             return new JsonContent(value);
         }
         }
@@ -203,6 +205,8 @@ namespace SharpGLTF.IO
         public T GetValue<T>(params IConvertible[] path)
         public T GetValue<T>(params IConvertible[] path)
             where T : IConvertible
             where T : IConvertible
         {
         {
+            Guard.NotNull(path, nameof(path));
+
             return _JsonStaticUtils.GetValue<T>(this._Content, path);
             return _JsonStaticUtils.GetValue<T>(this._Content, path);
         }
         }
 
 

+ 1 - 0
src/SharpGLTF.Core/Runtime/ArmatureInstance.cs

@@ -128,6 +128,7 @@ namespace SharpGLTF.Runtime
         public static void SetAnimationFrame(IEnumerable<NodeInstance> nodes, params (int TrackIdx, float Time, float Weight)[] blended)
         public static void SetAnimationFrame(IEnumerable<NodeInstance> nodes, params (int TrackIdx, float Time, float Weight)[] blended)
         {
         {
             Guard.NotNull(nodes, nameof(nodes));
             Guard.NotNull(nodes, nameof(nodes));
+            Guard.NotNull(blended, nameof(blended));
 
 
             Span<int> tracks = stackalloc int[blended.Length];
             Span<int> tracks = stackalloc int[blended.Length];
             Span<float> times = stackalloc float[blended.Length];
             Span<float> times = stackalloc float[blended.Length];

+ 42 - 22
src/SharpGLTF.Core/Schema2/gltf.MaterialChannel.cs

@@ -3,8 +3,6 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Numerics;
 using System.Numerics;
 
 
-using PARAMETER = System.Object;
-
 namespace SharpGLTF.Schema2
 namespace SharpGLTF.Schema2
 {
 {
     /// <summary>
     /// <summary>
@@ -27,6 +25,7 @@ namespace SharpGLTF.Schema2
             Guard.NotNullOrEmpty(key, nameof(key));
             Guard.NotNullOrEmpty(key, nameof(key));
 
 
             Guard.NotNull(texInfo, nameof(texInfo));
             Guard.NotNull(texInfo, nameof(texInfo));
+            Guard.NotNull(parameters, nameof(parameters));
 
 
             _Key = key;
             _Key = key;
             _Material = m;
             _Material = m;
@@ -40,10 +39,10 @@ namespace SharpGLTF.Schema2
         #region data
         #region data
 
 
         [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
         [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
-        private readonly String _Key;
+        private readonly Material _Material;
 
 
         [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
         [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
-        private readonly Material _Material;
+        private readonly String _Key;
 
 
         [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
         [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
         private readonly Func<Boolean, TextureInfo> _TextureInfo;
         private readonly Func<Boolean, TextureInfo> _TextureInfo;
@@ -51,11 +50,23 @@ namespace SharpGLTF.Schema2
         [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
         [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
         private readonly IReadOnlyList<IMaterialParameter> _Parameters;
         private readonly IReadOnlyList<IMaterialParameter> _Parameters;
 
 
+        /// <inheritdoc />
         public override int GetHashCode()
         public override int GetHashCode()
         {
         {
-            if (_Key == null) return 0;
+            if (_Material == null) return 0;
 
 
-            return _Key.GetHashCode() ^ _Material.GetHashCode();
+            return _Material.GetHashCode() ^ _Key.GetHashCode();
+        }
+
+        /// <inheritdoc />
+        public override bool Equals(object obj) { return obj is MaterialChannel other && Equals(other); }
+
+        public bool Equals(MaterialChannel other)
+        {
+            if (this._Material == null && other._Material == null) return true;
+            if (this._Material != other._Material) return false;
+            if (this._Key != other._Key) return false;
+            return true;
         }
         }
 
 
         #endregion
         #endregion
@@ -101,29 +112,21 @@ namespace SharpGLTF.Schema2
         {
         {
             get
             get
             {
             {
-                foreach (var p in _Parameters.OfType<_MaterialParameter<Vector4>>())
-                {
-                    if (p.Name == "RGBA") return p.Value;
-                }
+                var p4 = _Parameters.OfType<_MaterialParameter<Vector4>>().SingleOrDefault();
+                if (p4.Name == "RGBA") return p4.Value;
 
 
-                foreach (var p in _Parameters.OfType<_MaterialParameter<Vector3>>())
-                {
-                    if (p.Name == "RGB") return new Vector4(p.Value, 1);
-                }
+                var p3 = _Parameters.OfType<_MaterialParameter<Vector3>>().SingleOrDefault();
+                if (p3.Name == "RGB") return new Vector4(p3.Value, 1);
 
 
                 throw new InvalidOperationException("RGB or RGBA not found.");
                 throw new InvalidOperationException("RGB or RGBA not found.");
             }
             }
             set
             set
             {
             {
-                foreach (var p in _Parameters.OfType<_MaterialParameter<Vector4>>())
-                {
-                    if (p.Name == "RGBA") { p.Value = value; return; }
-                }
+                var p4 = _Parameters.OfType<_MaterialParameter<Vector4>>().SingleOrDefault();
+                if (p4.Name == "RGBA") { p4.Value = value; return; }
 
 
-                foreach (var p in _Parameters.OfType<_MaterialParameter<Vector3>>())
-                {
-                    if (p.Name == "RGB") { p.Value = new Vector3(value.X, value.Y, value.Z); return; }
-                }
+                var p3 = _Parameters.OfType<_MaterialParameter<Vector3>>().SingleOrDefault();
+                if (p3.Name == "RGB") { p3.Value = new Vector3(value.X, value.Y, value.Z); return; }
 
 
                 throw new InvalidOperationException("RGB or RGBA not found.");
                 throw new InvalidOperationException("RGB or RGBA not found.");
             }
             }
@@ -132,6 +135,23 @@ namespace SharpGLTF.Schema2
         #endregion
         #endregion
 
 
         #region API
         #region API
+
+        public float GetFactor(string key)
+        {
+            return _Parameters
+                .OfType<_MaterialParameter<float>>()
+                .Single(item => item.Name == key)
+                .Value;
+        }
+
+        public void SetFactor(string key, float value)
+        {
+            _Parameters
+                .OfType<_MaterialParameter<float>>()
+                .Single(item => item.Name == key)
+                .Value = value;
+        }
+
         private Texture _GetTexture()
         private Texture _GetTexture()
         {
         {
             var texInfo = _TextureInfo?.Invoke(false);
             var texInfo = _TextureInfo?.Invoke(false);

+ 128 - 130
src/SharpGLTF.Core/Schema2/gltf.MaterialParameter.cs

@@ -1,130 +1,128 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Numerics;
-
-namespace SharpGLTF.Schema2
-{
-    public interface IMaterialParameter
-    {
-        string Name { get; }
-
-        bool IsDefault { get; }
-
-        Type ValueType { get; }
-
-        /// <summary>
-        /// Gets or sets the value of this parameter. <br/>
-        /// Valid types are <see cref="float"/> <see cref="Vector3"/> and <see cref="Vector4"/>
-        /// </summary>
-        Object Value { get; set; }
-    }
-
-    [System.Diagnostics.DebuggerDisplay("[{_Key}, {Value}]")]
-    readonly struct _MaterialParameter<T> : IMaterialParameter
-        where T : unmanaged, IEquatable<T>
-    {
-        #region constants
-
-        internal enum Key
-        {
-            RGB,
-            RGBA,
-
-            NormalScale,
-            OcclusionStrength,
-
-            MetallicFactor,
-            RoughnessFactor,
-            SpecularFactor,
-            GlossinessFactor,
-            ClearCoatFactor,
-            ThicknessFactor,
-            TransmissionFactor,
-            AttenuationDistance,
-        }
-
-        #endregion
-
-        #region constructors
-
-        internal _MaterialParameter(Key key, T defval, Func<T> getter, Action<T> setter)
-        {
-            _Key = key;
-            _ValueDefault = defval;
-            _ValueGetter = () => getter();
-            _ValueSetter = value => setter(value);
-        }
-
-        #endregion
-
-        #region data
-
-        private readonly Key _Key;
-        private readonly T _ValueDefault;
-        private readonly Func<T> _ValueGetter;
-        private readonly Action<T> _ValueSetter;
-
-        #endregion
-
-        #region properties
-
-        public string Name => _Key.ToString();
-
-        public bool IsDefault => Value.Equals(_ValueDefault);
-
-        public Type ValueType => _ValueDefault.GetType();
-
-        public T Value
-        {
-            get => _ValueGetter();
-            set => _ValueSetter(value);
-        }
-
-        object IMaterialParameter.Value
-        {
-            get => _ValueGetter();
-            set => _ValueSetter((T)value);
-        }
-
-        #endregion
-
-        #region helpers
-        internal static Vector4 Combine(IReadOnlyList<IMaterialParameter> parameters)
-        {
-            Span<float> tmp = stackalloc float[4];
-            int idx = 0;
-
-            foreach (var p in parameters)
-            {
-                if (p is _MaterialParameter<Single> v1) { tmp[idx++] = v1.Value; }
-                if (p is _MaterialParameter<Vector2> v2) { tmp[idx++] = v2.Value.X; tmp[idx++] = v2.Value.Y; }
-                if (p is _MaterialParameter<Vector3> v3) { tmp[idx++] = v3.Value.X; tmp[idx++] = v3.Value.Y; tmp[idx++] = v3.Value.Z; }
-                if (p is _MaterialParameter<Vector4> v4) { tmp[idx++] = v4.Value.X; tmp[idx++] = v4.Value.Y; tmp[idx++] = v4.Value.Z; tmp[idx++] = v4.Value.W; }
-            }
-
-            return new Vector4(tmp[0], tmp[1], tmp[2], tmp[3]);
-        }
-
-        internal static void Apply(IReadOnlyList<IMaterialParameter> parameters, Vector4 value)
-        {
-            Span<float> tmp = stackalloc float[4];
-            tmp[0] = value.X;
-            tmp[1] = value.Y;
-            tmp[2] = value.Z;
-            tmp[3] = value.W;
-
-            int idx = 0;
-
-            foreach (var p in parameters)
-            {
-                if (p is _MaterialParameter<Single> v1) { v1.Value = tmp[idx++]; }
-                if (p is _MaterialParameter<Vector2> v2) { v2.Value = new Vector2(tmp[idx + 0], tmp[idx + 1]); idx += 2; }
-                if (p is _MaterialParameter<Vector3> v3) { v3.Value = new Vector3(tmp[idx + 0], tmp[idx + 1], tmp[idx + 2]); idx += 3; }
-                if (p is _MaterialParameter<Vector4> v4) { v4.Value = new Vector4(tmp[idx + 0], tmp[idx + 1], tmp[idx + 2], tmp[idx + 3]); idx += 4; }
-            }
-        }
-
-        #endregion
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Numerics;
+
+namespace SharpGLTF.Schema2
+{
+    public interface IMaterialParameter
+    {
+        string Name { get; }
+
+        bool IsDefault { get; }
+
+        Type ValueType { get; }
+
+        /// <summary>
+        /// Gets or sets the value of this parameter. <br/>
+        /// Valid types are <see cref="float"/> <see cref="Vector3"/> and <see cref="Vector4"/>
+        /// </summary>
+        Object Value { get; set; }
+    }
+
+    internal enum _MaterialParameterKey
+    {
+        Unknown = 0,
+
+        RGB,
+        RGBA,
+
+        NormalScale,
+        OcclusionStrength,
+
+        MetallicFactor,
+        RoughnessFactor,
+        SpecularFactor,
+        GlossinessFactor,
+        ClearCoatFactor,
+        ThicknessFactor,
+        TransmissionFactor,
+        AttenuationDistance,
+    }
+
+    [System.Diagnostics.DebuggerDisplay("{_Key} = {Value}")]
+    readonly struct _MaterialParameter<T> : IMaterialParameter
+        where T : unmanaged, IEquatable<T>
+    {
+        #region constructors
+
+        internal _MaterialParameter(_MaterialParameterKey key, T defval, Func<T> getter, Action<T> setter)
+        {
+            _Key = key;
+            _ValueDefault = defval;
+            _ValueGetter = () => getter();
+            _ValueSetter = value => setter(value);
+        }
+
+        #endregion
+
+        #region data
+
+        private readonly _MaterialParameterKey _Key;
+        private readonly T _ValueDefault;
+        private readonly Func<T> _ValueGetter;
+        private readonly Action<T> _ValueSetter;
+
+        #endregion
+
+        #region properties
+
+        public string Name => _Key.ToString();
+
+        public bool IsDefault => Value.Equals(_ValueDefault);
+
+        public Type ValueType => _ValueDefault.GetType();
+
+        public T Value
+        {
+            get => _ValueGetter();
+            set => _ValueSetter(value);
+        }
+
+        object IMaterialParameter.Value
+        {
+            get => _ValueGetter();
+            set => _ValueSetter((T)value);
+        }
+
+        #endregion
+
+        #region helpers
+        internal static Vector4 Combine(IReadOnlyList<IMaterialParameter> parameters)
+        {
+            Span<float> tmp = stackalloc float[4];
+            int idx = 0;
+
+            foreach (var p in parameters)
+            {
+                if (p is _MaterialParameter<Single> v1) { tmp[idx++] = v1.Value; }
+                if (p is _MaterialParameter<Vector2> v2) { tmp[idx++] = v2.Value.X; tmp[idx++] = v2.Value.Y; }
+                if (p is _MaterialParameter<Vector3> v3) { tmp[idx++] = v3.Value.X; tmp[idx++] = v3.Value.Y; tmp[idx++] = v3.Value.Z; }
+                if (p is _MaterialParameter<Vector4> v4) { tmp[idx++] = v4.Value.X; tmp[idx++] = v4.Value.Y; tmp[idx++] = v4.Value.Z; tmp[idx++] = v4.Value.W; }
+            }
+
+            return new Vector4(tmp[0], tmp[1], tmp[2], tmp[3]);
+        }
+
+        internal static void Apply(IReadOnlyList<IMaterialParameter> parameters, Vector4 value)
+        {
+            Span<float> tmp = stackalloc float[4];
+            tmp[0] = value.X;
+            tmp[1] = value.Y;
+            tmp[2] = value.Z;
+            tmp[3] = value.W;
+
+            int idx = 0;
+
+            foreach (var p in parameters)
+            {
+                if (p is _MaterialParameter<Single> v1) { v1.Value = tmp[idx++]; }
+                if (p is _MaterialParameter<Vector2> v2) { v2.Value = new Vector2(tmp[idx + 0], tmp[idx + 1]); idx += 2; }
+                if (p is _MaterialParameter<Vector3> v3) { v3.Value = new Vector3(tmp[idx + 0], tmp[idx + 1], tmp[idx + 2]); idx += 3; }
+                if (p is _MaterialParameter<Vector4> v4) { v4.Value = new Vector4(tmp[idx + 0], tmp[idx + 1], tmp[idx + 2], tmp[idx + 3]); idx += 4; }
+            }
+        }
+
+        #endregion
+    }
+}

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

@@ -106,19 +106,19 @@ namespace SharpGLTF.Schema2
             if (channels != null) { foreach (var c in channels) yield return c; }
             if (channels != null) { foreach (var c in channels) yield return c; }
 
 
             var normalParam = new _MaterialParameter<float>(
             var normalParam = new _MaterialParameter<float>(
-                _MaterialParameter<float>.Key.NormalScale,
+                _MaterialParameterKey.NormalScale,
                 MaterialNormalTextureInfo.ScaleDefault,
                 MaterialNormalTextureInfo.ScaleDefault,
                 () => _GetNormalTexture(false)?.Scale ?? MaterialNormalTextureInfo.ScaleDefault,
                 () => _GetNormalTexture(false)?.Scale ?? MaterialNormalTextureInfo.ScaleDefault,
                 value => _GetNormalTexture(true).Scale = value);
                 value => _GetNormalTexture(true).Scale = value);
 
 
             var occlusionParam = new _MaterialParameter<float>(
             var occlusionParam = new _MaterialParameter<float>(
-                _MaterialParameter<float>.Key.OcclusionStrength,
+                _MaterialParameterKey.OcclusionStrength,
                 MaterialOcclusionTextureInfo.StrengthDefault,
                 MaterialOcclusionTextureInfo.StrengthDefault,
                 () => _GetOcclusionTexture(false)?.Strength ?? MaterialOcclusionTextureInfo.StrengthDefault,
                 () => _GetOcclusionTexture(false)?.Strength ?? MaterialOcclusionTextureInfo.StrengthDefault,
                 value => _GetOcclusionTexture(true).Strength = value);
                 value => _GetOcclusionTexture(true).Strength = value);
 
 
             var emissiveParam = new _MaterialParameter<Vector3>(
             var emissiveParam = new _MaterialParameter<Vector3>(
-                _MaterialParameter<Vector3>.Key.RGB,
+                _MaterialParameterKey.RGB,
                 _emissiveFactorDefault,
                 _emissiveFactorDefault,
                 () => this._emissiveFactor.AsValue(_emissiveFactorDefault),
                 () => this._emissiveFactor.AsValue(_emissiveFactorDefault),
                 value => this._emissiveFactor = value.AsNullable(_emissiveFactorDefault, Vector3.Zero, Vector3.One));
                 value => this._emissiveFactor = value.AsNullable(_emissiveFactorDefault, Vector3.Zero, Vector3.One));
@@ -206,9 +206,9 @@ namespace SharpGLTF.Schema2
 
 
         public IEnumerable<MaterialChannel> GetChannels(Material material)
         public IEnumerable<MaterialChannel> GetChannels(Material material)
         {
         {
-            var colorParam = new _MaterialParameter<Vector4>(_MaterialParameter<Vector4>.Key.RGBA, _baseColorFactorDefault, () => Color, v => Color = v);
-            var metallicParam = new _MaterialParameter<float>(_MaterialParameter<float>.Key.MetallicFactor, (float)_metallicFactorDefault, () => MetallicFactor, v => MetallicFactor = v);
-            var roughnessParam = new _MaterialParameter<float>(_MaterialParameter<float>.Key.RoughnessFactor, (float)_roughnessFactorDefault, () => RoughnessFactor, v => RoughnessFactor = v);
+            var colorParam = new _MaterialParameter<Vector4>(_MaterialParameterKey.RGBA, _baseColorFactorDefault, () => Color, v => Color = v);
+            var metallicParam = new _MaterialParameter<float>(_MaterialParameterKey.MetallicFactor, (float)_metallicFactorDefault, () => MetallicFactor, v => MetallicFactor = v);
+            var roughnessParam = new _MaterialParameter<float>(_MaterialParameterKey.RoughnessFactor, (float)_roughnessFactorDefault, () => RoughnessFactor, v => RoughnessFactor = v);
 
 
             yield return new MaterialChannel(material, "BaseColor", _GetBaseTexture, colorParam);
             yield return new MaterialChannel(material, "BaseColor", _GetBaseTexture, colorParam);
             yield return new MaterialChannel(material, "MetallicRoughness", _GetMetallicTexture, metallicParam, roughnessParam);
             yield return new MaterialChannel(material, "MetallicRoughness", _GetMetallicTexture, metallicParam, roughnessParam);
@@ -275,9 +275,9 @@ namespace SharpGLTF.Schema2
 
 
         public IEnumerable<MaterialChannel> GetChannels(Material material)
         public IEnumerable<MaterialChannel> GetChannels(Material material)
         {
         {
-            var diffuseParam = new _MaterialParameter<Vector4>(_MaterialParameter<Vector4>.Key.RGBA, _diffuseFactorDefault, () => DiffuseFactor, v => DiffuseFactor = v);
-            var specularParam = new _MaterialParameter<Vector3>(_MaterialParameter<Vector3>.Key.SpecularFactor, _specularFactorDefault, () => SpecularFactor, v => SpecularFactor = v);
-            var glossinessParam = new _MaterialParameter<float>(_MaterialParameter<float>.Key.GlossinessFactor, (float)_glossinessFactorDefault, () => GlossinessFactor, v => GlossinessFactor = v);
+            var diffuseParam = new _MaterialParameter<Vector4>(_MaterialParameterKey.RGBA, _diffuseFactorDefault, () => DiffuseFactor, v => DiffuseFactor = v);
+            var specularParam = new _MaterialParameter<Vector3>(_MaterialParameterKey.SpecularFactor, _specularFactorDefault, () => SpecularFactor, v => SpecularFactor = v);
+            var glossinessParam = new _MaterialParameter<float>(_MaterialParameterKey.GlossinessFactor, (float)_glossinessFactorDefault, () => GlossinessFactor, v => GlossinessFactor = v);
 
 
             yield return new MaterialChannel(material, "Diffuse", _GetDiffuseTexture, diffuseParam);
             yield return new MaterialChannel(material, "Diffuse", _GetDiffuseTexture, diffuseParam);
             yield return new MaterialChannel(material, "SpecularGlossiness", _GetGlossinessTexture, specularParam, glossinessParam);
             yield return new MaterialChannel(material, "SpecularGlossiness", _GetGlossinessTexture, specularParam, glossinessParam);
@@ -349,9 +349,9 @@ namespace SharpGLTF.Schema2
 
 
         public IEnumerable<MaterialChannel> GetChannels(Material material)
         public IEnumerable<MaterialChannel> GetChannels(Material material)
         {
         {
-            var clearCoatParam = new _MaterialParameter<float>(_MaterialParameter<float>.Key.ClearCoatFactor, (float)_clearcoatFactorDefault, () => ClearCoatFactor, v => ClearCoatFactor = v);
-            var roughnessParam = new _MaterialParameter<float>(_MaterialParameter<float>.Key.RoughnessFactor, (float)_clearcoatRoughnessFactorDefault, () => RoughnessFactor, v => RoughnessFactor = v);
-            var normScaleParam = new _MaterialParameter<float>(_MaterialParameter<float>.Key.NormalScale,
+            var clearCoatParam = new _MaterialParameter<float>(_MaterialParameterKey.ClearCoatFactor, (float)_clearcoatFactorDefault, () => ClearCoatFactor, v => ClearCoatFactor = v);
+            var roughnessParam = new _MaterialParameter<float>(_MaterialParameterKey.RoughnessFactor, (float)_clearcoatRoughnessFactorDefault, () => RoughnessFactor, v => RoughnessFactor = v);
+            var normScaleParam = new _MaterialParameter<float>(_MaterialParameterKey.NormalScale,
                 MaterialNormalTextureInfo.ScaleDefault,
                 MaterialNormalTextureInfo.ScaleDefault,
                 () => _GetClearCoatNormalTexture(false)?.Scale ?? MaterialNormalTextureInfo.ScaleDefault,
                 () => _GetClearCoatNormalTexture(false)?.Scale ?? MaterialNormalTextureInfo.ScaleDefault,
                 v => _GetClearCoatNormalTexture(true).Scale = v);
                 v => _GetClearCoatNormalTexture(true).Scale = v);
@@ -391,7 +391,7 @@ namespace SharpGLTF.Schema2
 
 
         public IEnumerable<MaterialChannel> GetChannels(Material material)
         public IEnumerable<MaterialChannel> GetChannels(Material material)
         {
         {
-            var transmissionParam = new _MaterialParameter<float>(_MaterialParameter<float>.Key.TransmissionFactor, (float)_transmissionFactorDefault, () => TransmissionFactor, v => TransmissionFactor = v);
+            var transmissionParam = new _MaterialParameter<float>(_MaterialParameterKey.TransmissionFactor, (float)_transmissionFactorDefault, () => TransmissionFactor, v => TransmissionFactor = v);
 
 
             yield return new MaterialChannel(material, "Transmission", _GetTransmissionTexture, transmissionParam);
             yield return new MaterialChannel(material, "Transmission", _GetTransmissionTexture, transmissionParam);
         }
         }
@@ -445,8 +445,8 @@ namespace SharpGLTF.Schema2
 
 
         public IEnumerable<MaterialChannel> GetChannels(Material material)
         public IEnumerable<MaterialChannel> GetChannels(Material material)
         {
         {
-            var colorParam = new _MaterialParameter<Vector3>(_MaterialParameter<Vector3>.Key.RGB, _sheenColorFactorDefault, () => ColorFactor, v => ColorFactor = v);
-            var roughnessParam = new _MaterialParameter<float>(_MaterialParameter<float>.Key.RoughnessFactor, _sheenRoughnessFactorDefault, () => RoughnessFactor, v => RoughnessFactor = v);
+            var colorParam = new _MaterialParameter<Vector3>(_MaterialParameterKey.RGB, _sheenColorFactorDefault, () => ColorFactor, v => ColorFactor = v);
+            var roughnessParam = new _MaterialParameter<float>(_MaterialParameterKey.RoughnessFactor, _sheenRoughnessFactorDefault, () => RoughnessFactor, v => RoughnessFactor = v);
 
 
             yield return new MaterialChannel(material, "SheenColor", _GetSheenColorTexture, colorParam);
             yield return new MaterialChannel(material, "SheenColor", _GetSheenColorTexture, colorParam);
             yield return new MaterialChannel(material, "SheenRoughness", _GetSheenRoughnessTexture, roughnessParam);
             yield return new MaterialChannel(material, "SheenRoughness", _GetSheenRoughnessTexture, roughnessParam);
@@ -542,8 +542,8 @@ namespace SharpGLTF.Schema2
 
 
         public IEnumerable<MaterialChannel> GetChannels(Material material)
         public IEnumerable<MaterialChannel> GetChannels(Material material)
         {
         {
-            var colorParam = new _MaterialParameter<Vector3>(_MaterialParameter<Vector3>.Key.RGB, _specularColorFactorDefault, () => SpecularColor, v => SpecularColor = v);
-            var factorParam = new _MaterialParameter<float>(_MaterialParameter<float>.Key.SpecularFactor, (float)_specularFactorDefault, () => SpecularFactor, v => SpecularFactor = v);
+            var colorParam = new _MaterialParameter<Vector3>(_MaterialParameterKey.RGB, _specularColorFactorDefault, () => SpecularColor, v => SpecularColor = v);
+            var factorParam = new _MaterialParameter<float>(_MaterialParameterKey.SpecularFactor, (float)_specularFactorDefault, () => SpecularFactor, v => SpecularFactor = v);
 
 
             yield return new MaterialChannel(material, "SpecularColor", _GetSpecularColorTexture, colorParam);
             yield return new MaterialChannel(material, "SpecularColor", _GetSpecularColorTexture, colorParam);
             yield return new MaterialChannel(material, "SpecularFactor", _GetSpecularFactorTexture, factorParam);
             yield return new MaterialChannel(material, "SpecularFactor", _GetSpecularFactorTexture, factorParam);
@@ -604,9 +604,9 @@ namespace SharpGLTF.Schema2
 
 
         public IEnumerable<MaterialChannel> GetChannels(Material material)
         public IEnumerable<MaterialChannel> GetChannels(Material material)
         {
         {
-            var thicknessParam = new _MaterialParameter<float>(_MaterialParameter<float>.Key.ThicknessFactor, (float)_thicknessFactorDefault, () => ThicknessFactor, v => ThicknessFactor = v);
-            var attColorParam = new _MaterialParameter<Vector3>(_MaterialParameter<Vector3>.Key.RGB, _attenuationColorDefault, () => AttenuationColor, v => AttenuationColor = v);
-            var attDistParam = new _MaterialParameter<float>(_MaterialParameter<float>.Key.AttenuationDistance, 0, () => AttenuationDistance, v => AttenuationDistance = v);
+            var thicknessParam = new _MaterialParameter<float>(_MaterialParameterKey.ThicknessFactor, (float)_thicknessFactorDefault, () => ThicknessFactor, v => ThicknessFactor = v);
+            var attColorParam = new _MaterialParameter<Vector3>(_MaterialParameterKey.RGB, _attenuationColorDefault, () => AttenuationColor, v => AttenuationColor = v);
+            var attDistParam = new _MaterialParameter<float>(_MaterialParameterKey.AttenuationDistance, 0, () => AttenuationDistance, v => AttenuationDistance = v);
 
 
             yield return new MaterialChannel(material, "VolumeThickness", _GetThicknessTexture, thicknessParam);
             yield return new MaterialChannel(material, "VolumeThickness", _GetThicknessTexture, thicknessParam);
             yield return new MaterialChannel(material, "VolumeAttenuation", onCreate => null, attColorParam, attDistParam);
             yield return new MaterialChannel(material, "VolumeAttenuation", onCreate => null, attColorParam, attDistParam);

+ 42 - 1
src/SharpGLTF.Core/Schema2/gltf.Node.cs

@@ -348,6 +348,15 @@ namespace SharpGLTF.Schema2
 
 
         #region API - Transforms
         #region API - Transforms
 
 
+        /// <summary>
+        /// Gets the local transform of this node in a given animation at a given time.
+        /// </summary>
+        /// <param name="animation">the animation to sample.</param>
+        /// <param name="time">the time offset within the animation.</param>
+        /// <returns>the sampled transform.</returns>
+        /// <remarks>
+        /// This is a convenience method, but it's slow, it's better to cache <see cref="GetCurveSamplers(Animation)"/>.
+        /// </remarks>
         public TRANSFORM GetLocalTransform(Animation animation, float time)
         public TRANSFORM GetLocalTransform(Animation animation, float time)
         {
         {
             if (animation == null) return this.LocalTransform;
             if (animation == null) return this.LocalTransform;
@@ -355,6 +364,15 @@ namespace SharpGLTF.Schema2
             return this.GetCurveSamplers(animation).GetLocalTransform(time);
             return this.GetCurveSamplers(animation).GetLocalTransform(time);
         }
         }
 
 
+        /// <summary>
+        /// Gets the world matrix of this node in a given animation at a given time.
+        /// </summary>
+        /// <param name="animation">the animation to sample.</param>
+        /// <param name="time">the time offset within the animation.</param>
+        /// <returns>the sampled transform.</returns>
+        /// <remarks>
+        /// This is a convenience method, but it's slow, it's better to cache <see cref="GetCurveSamplers(Animation)"/>.
+        /// </remarks>
         public Matrix4x4 GetWorldMatrix(Animation animation, float time)
         public Matrix4x4 GetWorldMatrix(Animation animation, float time)
         {
         {
             if (animation == null) return this.WorldMatrix;
             if (animation == null) return this.WorldMatrix;
@@ -731,7 +749,7 @@ namespace SharpGLTF.Schema2
     /// Use <see cref="Node.GetCurveSamplers(Animation)"/> for access.
     /// Use <see cref="Node.GetCurveSamplers(Animation)"/> for access.
     /// </summary>
     /// </summary>
     [System.Diagnostics.DebuggerDisplay("{_GetDebuggerDisplay(),nq}")]
     [System.Diagnostics.DebuggerDisplay("{_GetDebuggerDisplay(),nq}")]
-    public readonly struct NodeCurveSamplers
+    public readonly struct NodeCurveSamplers : IEquatable<NodeCurveSamplers>
     {
     {
         #region debug
         #region debug
 
 
@@ -792,6 +810,29 @@ namespace SharpGLTF.Schema2
         private readonly AnimationSampler _TranslationSampler;
         private readonly AnimationSampler _TranslationSampler;
         private readonly AnimationSampler _MorphSampler;
         private readonly AnimationSampler _MorphSampler;
 
 
+        /// <inheritdoc />
+        public override int GetHashCode()
+        {
+            return TargetNode.GetHashCode() ^ Animation.GetHashCode();
+        }
+
+        /// <inheritdoc />
+        public override bool Equals(object obj)
+        {
+            return base.Equals(obj);
+        }
+
+        public static bool operator ==(in NodeCurveSamplers a, in NodeCurveSamplers b) => a.Equals(b);
+        public static bool operator !=(in NodeCurveSamplers a, in NodeCurveSamplers b) => !a.Equals(b);
+
+        /// <inheritdoc />
+        public bool Equals(NodeCurveSamplers other)
+        {
+            if (this.TargetNode != other.TargetNode) return false;
+            if (this.Animation != other.Animation) return false;
+            return true;
+        }
+
         #endregion
         #endregion
 
 
         #region  properties
         #region  properties

+ 1 - 1
src/SharpGLTF.Core/Schema2/gltf.Textures.cs

@@ -393,7 +393,7 @@ namespace SharpGLTF.Schema2
                 return null;
                 return null;
             }
             }
 
 
-            if (primary  != null) Guard.MustShareLogicalParent(this, "this", primary, nameof(primary));
+            Guard.MustShareLogicalParent(this, "this", primary, nameof(primary));
             if (fallback != null) Guard.MustShareLogicalParent(this, "this", fallback, nameof(primary));
             if (fallback != null) Guard.MustShareLogicalParent(this, "this", fallback, nameof(primary));
             if (sampler  != null) Guard.MustShareLogicalParent(this, "this", sampler, nameof(sampler));
             if (sampler  != null) Guard.MustShareLogicalParent(this, "this", sampler, nameof(sampler));
 
 

+ 13 - 0
src/SharpGLTF.Core/Transforms/IndexWeight.cs

@@ -44,6 +44,19 @@ namespace SharpGLTF.Transforms
         public readonly int Index;
         public readonly int Index;
         public readonly float Weight;
         public readonly float Weight;
 
 
+        /// <inheritdoc/>
+        public override int GetHashCode()
+        {
+            return Index.GetHashCode() ^ Weight.GetHashCode();
+        }
+
+        /// <inheritdoc/>
+        public override bool Equals(object obj)
+        {
+            return obj is IndexWeight other && this.Equals(other);
+        }
+
+        /// <inheritdoc/>
         public bool Equals(IndexWeight other)
         public bool Equals(IndexWeight other)
         {
         {
             return this.Index == other.Index && this.Weight == other.Weight;
             return this.Index == other.Index && this.Weight == other.Weight;

+ 23 - 1
src/SharpGLTF.Toolkit/Collections/Triple.cs

@@ -5,7 +5,7 @@ using System.Text;
 
 
 namespace SharpGLTF.Collections
 namespace SharpGLTF.Collections
 {
 {
-    public readonly struct Triple<T> : IReadOnlyList<T>
+    public readonly struct Triple<T> : IReadOnlyList<T>, IEquatable<Triple<T>>
     {
     {
         public static implicit operator Triple<T>(in (T A, T B, T C) triple)
         public static implicit operator Triple<T>(in (T A, T B, T C) triple)
         {
         {
@@ -23,6 +23,28 @@ namespace SharpGLTF.Collections
         public readonly T B;
         public readonly T B;
         public readonly T C;
         public readonly T C;
 
 
+        public override int GetHashCode()
+        {
+            int h = 0;
+            h ^= A?.GetHashCode() ?? 0;
+            h ^= B?.GetHashCode() ?? 0;
+            h ^= C?.GetHashCode() ?? 0;
+            return h;
+        }
+
+        public override bool Equals(object obj)
+        {
+            return obj is Triple<T> && Equals((Triple<T>)obj);
+        }
+
+        public bool Equals(Triple<T> other)
+        {
+            if (!this.A.Equals(other.A)) return false;
+            if (!this.B.Equals(other.B)) return false;
+            if (!this.C.Equals(other.C)) return false;
+            return true;
+        }
+
         public int Count => 3;
         public int Count => 3;
 
 
         public T this[int index]
         public T this[int index]

+ 1 - 3
src/SharpGLTF.Toolkit/IO/Zip.cs

@@ -155,9 +155,7 @@ namespace SharpGLTF.IO
 
 
             var baseName = System.IO.Path.GetFileNameWithoutExtension(filePath);
             var baseName = System.IO.Path.GetFileNameWithoutExtension(filePath);
 
 
-            bool isGltfExtension = filePath
-                .ToLower(System.Globalization.CultureInfo.InvariantCulture)
-                .EndsWith(".gltf", StringComparison.OrdinalIgnoreCase);
+            bool isGltfExtension = filePath.EndsWith(".GLTF", StringComparison.OrdinalIgnoreCase);
 
 
             var context = WriteContext.Create(_WriteAsset);
             var context = WriteContext.Create(_WriteAsset);
 
 

+ 9 - 9
src/SharpGLTF.Toolkit/Scenes/SceneBuilder.Schema2.cs

@@ -386,17 +386,17 @@ namespace SharpGLTF.Scenes
         {
         {
             if (a.InterpolationMode == AnimationInterpolationMode.CUBICSPLINE)
             if (a.InterpolationMode == AnimationInterpolationMode.CUBICSPLINE)
             {
             {
-                if (b.MaxDegree != 3) throw new ArgumentException(nameof(b.MaxDegree));
+                if (b.MaxDegree != 3) throw new ArgumentException("MaxDegree must be 3", nameof(b));
 
 
                 var bb = b.ToSplineCurve();
                 var bb = b.ToSplineCurve();
 
 
                 foreach (var (ak, av) in a.GetCubicKeys())
                 foreach (var (ak, av) in a.GetCubicKeys())
                 {
                 {
-                    if (!bb.TryGetValue(ak, out var bv)) throw new ArgumentException(nameof(b));
+                    if (!bb.TryGetValue(ak, out var bv)) throw new ArgumentException($"Missing key {ak}", nameof(b));
 
 
-                    if (!equalityComparer(av.TangentIn, bv.TangentIn)) throw new ArgumentException(nameof(b));
-                    if (!equalityComparer(av.Value, bv.Value)) throw new ArgumentException(nameof(b));
-                    if (!equalityComparer(av.TangentOut, bv.TangentOut)) throw new ArgumentException(nameof(b));
+                    if (!equalityComparer(av.TangentIn, bv.TangentIn)) throw new ArgumentException("Conversion failed.", nameof(b));
+                    if (!equalityComparer(av.Value, bv.Value)) throw new ArgumentException("Conversion failed.", nameof(b));
+                    if (!equalityComparer(av.TangentOut, bv.TangentOut)) throw new ArgumentException("Conversion failed.", nameof(b));
                 }
                 }
             }
             }
             else if (a.InterpolationMode == AnimationInterpolationMode.LINEAR)
             else if (a.InterpolationMode == AnimationInterpolationMode.LINEAR)
@@ -407,8 +407,8 @@ namespace SharpGLTF.Scenes
 
 
                 foreach (var (ak, av) in a.GetLinearKeys())
                 foreach (var (ak, av) in a.GetLinearKeys())
                 {
                 {
-                    if (!bb.TryGetValue(ak, out var bv)) throw new ArgumentException(nameof(b));
-                    if (!equalityComparer(av, bv)) throw new ArgumentException(nameof(b));
+                    if (!bb.TryGetValue(ak, out var bv)) throw new ArgumentException($"Missing key {ak}", nameof(b));
+                    if (!equalityComparer(av, bv)) throw new ArgumentException("Conversion failed.", nameof(b));
                 }
                 }
             }
             }
 
 
@@ -420,8 +420,8 @@ namespace SharpGLTF.Scenes
 
 
                 foreach (var (ak, av) in a.GetLinearKeys())
                 foreach (var (ak, av) in a.GetLinearKeys())
                 {
                 {
-                    if (!bb.TryGetValue(ak, out var bv)) throw new ArgumentException(nameof(b));
-                    if (!equalityComparer(av, bv)) throw new ArgumentException(nameof(b));
+                    if (!bb.TryGetValue(ak, out var bv)) throw new ArgumentException($"Missing key {ak}", nameof(b));
+                    if (!equalityComparer(av, bv)) throw new ArgumentException("Conversion failed.", nameof(b));
                 }
                 }
             }
             }
         }
         }

+ 30 - 3
src/SharpGLTF.Toolkit/Schema2/MaterialExtensions.cs

@@ -52,6 +52,7 @@ namespace SharpGLTF.Schema2
             return material;
             return material;
         }
         }
 
 
+        [Obsolete("don't use vector4 based parameter. Use WithChannelColor and WithChannelFactor instead.")]
         public static Material WithChannelParameter(this Material material, string channelName, Vector4 parameter)
         public static Material WithChannelParameter(this Material material, string channelName, Vector4 parameter)
         {
         {
             Guard.NotNull(material, nameof(material));
             Guard.NotNull(material, nameof(material));
@@ -63,6 +64,28 @@ namespace SharpGLTF.Schema2
             return material;
             return material;
         }
         }
 
 
+        public static Material WithChannelColor(this Material material, string channelName, Vector4 color)
+        {
+            Guard.NotNull(material, nameof(material));
+
+            var channel = material.FindChannel(channelName).Value;
+
+            channel.Color = color;
+
+            return material;
+        }
+
+        public static Material WithChannelFactor(this Material material, string channelName, string paramName, float factor)
+        {
+            Guard.NotNull(material, nameof(material));
+
+            var channel = material.FindChannel(channelName).Value;
+
+            channel.SetFactor(paramName, factor);
+
+            return material;
+        }
+
         public static Material WithChannelTexture(this Material material, string channelName, int textureSet, string imageFilePath)
         public static Material WithChannelTexture(this Material material, string channelName, int textureSet, string imageFilePath)
         {
         {
             Guard.NotNull(material, nameof(material));
             Guard.NotNull(material, nameof(material));
@@ -105,10 +128,13 @@ namespace SharpGLTF.Schema2
             float roughnessFactor = 1
             float roughnessFactor = 1
             )
             )
         {
         {
-            material.WithPBRMetallicRoughness();
+            Guard.NotNull(material, nameof(material));
 
 
-            material.WithChannelParameter("BaseColor", baseColor);
-            material.WithChannelParameter("MetallicRoughness", new Vector4(metallicFactor, roughnessFactor, 0, 0));
+            material
+                .WithPBRMetallicRoughness()
+                .WithChannelColor("BaseColor", baseColor)
+                .WithChannelFactor("MetallicRoughness", "MetallicFactor", metallicFactor)
+                .WithChannelFactor("MetallicRoughness", "RoughnessFactor", roughnessFactor);
 
 
             if (!string.IsNullOrWhiteSpace(baseColorImageFilePath)) material.WithChannelTexture("BaseColor", 0, baseColorImageFilePath);
             if (!string.IsNullOrWhiteSpace(baseColorImageFilePath)) material.WithChannelTexture("BaseColor", 0, baseColorImageFilePath);
             if (!string.IsNullOrWhiteSpace(metallicImageFilePath)) material.WithChannelTexture("Metallic", 0, baseColorImageFilePath);
             if (!string.IsNullOrWhiteSpace(metallicImageFilePath)) material.WithChannelTexture("Metallic", 0, baseColorImageFilePath);
@@ -121,6 +147,7 @@ namespace SharpGLTF.Schema2
         /// </summary>
         /// </summary>
         /// <param name="material">The <see cref="Material"/> instance to set.</param>
         /// <param name="material">The <see cref="Material"/> instance to set.</param>
         /// <returns>This <see cref="Material"/> instance.</returns>
         /// <returns>This <see cref="Material"/> instance.</returns>
+        [Obsolete("SpecularGlossiness Extension has been declared deprecated by the Khronos Group. Use newer extensions instead.")]
         public static Material WithPBRSpecularGlossiness(this Material material)
         public static Material WithPBRSpecularGlossiness(this Material material)
         {
         {
             Guard.NotNull(material, nameof(material));
             Guard.NotNull(material, nameof(material));

+ 6 - 6
tests/SharpGLTF.Core.Tests/Schema2/Authoring/ExtensionsCreationTests.cs

@@ -118,8 +118,8 @@ namespace SharpGLTF.Schema2.Authoring
             scene.AddRigidMesh(mesh, Matrix4x4.Identity);
             scene.AddRigidMesh(mesh, Matrix4x4.Identity);
 
 
             var gltf2 = scene.ToGltf2();
             var gltf2 = scene.ToGltf2();
-            var clearCoatFactor = gltf2.LogicalMaterials[0].FindChannel("ClearCoat").Value.Parameter;
-            Assert.AreEqual(new Vector4(0.5f, 0, 0, 0), clearCoatFactor);
+            var clearCoatFactor = gltf2.LogicalMaterials[0].FindChannel("ClearCoat").Value.GetFactor("ClearCoatFactor");
+            Assert.AreEqual(0.5f, clearCoatFactor);
 
 
             scene.AttachToCurrentTest("result.glb");
             scene.AttachToCurrentTest("result.glb");
             scene.AttachToCurrentTest("result.gltf");
             scene.AttachToCurrentTest("result.gltf");
@@ -155,8 +155,8 @@ namespace SharpGLTF.Schema2.Authoring
             scene.AddRigidMesh(mesh, Matrix4x4.Identity);
             scene.AddRigidMesh(mesh, Matrix4x4.Identity);
 
 
             var gltf2 = scene.ToGltf2();
             var gltf2 = scene.ToGltf2();
-            var transmissionFactor = gltf2.LogicalMaterials[0].FindChannel("Transmission").Value.Parameter;
-            Assert.AreEqual(new Vector4(0.75f, 0, 0, 0), transmissionFactor);
+            var transmissionFactor = gltf2.LogicalMaterials[0].FindChannel("Transmission").Value.GetFactor("TransmissionFactor");
+            Assert.AreEqual(0.75f, transmissionFactor);
 
 
             scene.AttachToCurrentTest("result.glb");
             scene.AttachToCurrentTest("result.glb");
             scene.AttachToCurrentTest("result.gltf");            
             scene.AttachToCurrentTest("result.gltf");            
@@ -197,8 +197,8 @@ namespace SharpGLTF.Schema2.Authoring
             var sheenColorFactor = gltf2.LogicalMaterials[0].FindChannel("SheenColor").Value.Color;
             var sheenColorFactor = gltf2.LogicalMaterials[0].FindChannel("SheenColor").Value.Color;
             Assert.AreEqual(Vector4.One, sheenColorFactor);
             Assert.AreEqual(Vector4.One, sheenColorFactor);
 
 
-            var sheenRoughnessFactor = gltf2.LogicalMaterials[0].FindChannel("SheenRoughness").Value.Parameter;
-            Assert.AreEqual(new Vector4(0.5f, 0, 0, 0), sheenRoughnessFactor);
+            var sheenRoughnessFactor = gltf2.LogicalMaterials[0].FindChannel("SheenRoughness").Value.GetFactor("RoughnessFactor");
+            Assert.AreEqual(0.5f, sheenRoughnessFactor);
 
 
             scene.AttachToCurrentTest("result.glb");
             scene.AttachToCurrentTest("result.glb");
             scene.AttachToCurrentTest("result.gltf");
             scene.AttachToCurrentTest("result.gltf");