Browse Source

API changes in geometry transforms.

Vicente Penades 6 years ago
parent
commit
b198e65edf

+ 134 - 91
src/SharpGLTF.Core/Schema2/gltf.Node.cs

@@ -80,32 +80,78 @@ namespace SharpGLTF.Schema2
 
         #endregion
 
-        #region properties - transform
+        #region properties - content
 
         /// <summary>
-        /// Gets or sets the local transform <see cref="Matrix4x4"/> of this <see cref="Node"/>.
+        /// Gets or sets the <see cref="Schema2.Camera"/> of this <see cref="Node"/>.
         /// </summary>
-        public Matrix4x4 LocalMatrix
+        public Camera Camera
         {
-            get => Transforms.AffineTransform.Evaluate(_matrix, _scale, _rotation, _translation);
+            get => this._camera.HasValue ? this.LogicalParent.LogicalCameras[this._camera.Value] : null;
             set
             {
-                if (value == Matrix4x4.Identity)
-                {
-                    _matrix = null;
-                }
-                else
-                {
-                    Guard.IsFalse(this._skin.HasValue, _NOTRANSFORMMESSAGE);
-                    _matrix = value;
-                }
+                if (value == null) { this._camera = null; return; }
 
-                _scale = null;
-                _rotation = null;
-                _translation = null;
+                Guard.MustShareLogicalParent(this.LogicalParent, nameof(this.LogicalParent), value, nameof(value));
+
+                this._camera = value.LogicalIndex;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the <see cref="Schema2.Mesh"/> of this <see cref="Node"/>.
+        /// </summary>
+        public Mesh Mesh
+        {
+            get => this._mesh.HasValue ? this.LogicalParent.LogicalMeshes[this._mesh.Value] : null;
+            set
+            {
+                if (value == null) { this._mesh = null; return; }
+
+                Guard.MustShareLogicalParent(this.LogicalParent, nameof(this.LogicalParent), value, nameof(value));
+
+                this._mesh = value.LogicalIndex;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the <see cref="Schema2.Skin"/> of this <see cref="Node"/>.
+        /// </summary>
+        public Skin Skin
+        {
+            get => this._skin.HasValue ? this.LogicalParent.LogicalSkins[this._skin.Value] : null;
+            set
+            {
+                if (value == null) { this._skin = null; return; }
+
+                Guard.MustShareLogicalParent(this.LogicalParent, nameof(this.LogicalParent), value, nameof(value));
+
+                Guard.IsFalse(_matrix.HasValue, _NOTRANSFORMMESSAGE);
+                Guard.IsFalse(_scale.HasValue, _NOTRANSFORMMESSAGE);
+                Guard.IsFalse(_rotation.HasValue, _NOTRANSFORMMESSAGE);
+                Guard.IsFalse(_translation.HasValue, _NOTRANSFORMMESSAGE);
+
+                this._skin = value.LogicalIndex;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the Morph Weights of this <see cref="Node"/>.
+        /// </summary>
+        public IReadOnlyList<Single> MorphWeights
+        {
+            get => _weights.Count == 0 ? Mesh?.MorphWeights : _weights.Select(item => (float)item).ToList();
+            set
+            {
+                _weights.Clear();
+                if (value != null) _weights.AddRange(value.Select(item => (Double)item));
             }
         }
 
+        #endregion
+
+        #region properties - transform
+
         /// <summary>
         /// Gets or sets the local Scale, Rotation and Translation of this <see cref="Node"/>.
         /// </summary>
@@ -125,11 +171,28 @@ namespace SharpGLTF.Schema2
             }
         }
 
-        public Transforms.AffineTransform GetLocalTransform(Animation animation, float time)
+        /// <summary>
+        /// Gets or sets the local transform <see cref="Matrix4x4"/> of this <see cref="Node"/>.
+        /// </summary>
+        public Matrix4x4 LocalMatrix
         {
-            if (animation == null) return this.LocalTransform;
+            get => Transforms.AffineTransform.Evaluate(_matrix, _scale, _rotation, _translation);
+            set
+            {
+                if (value == Matrix4x4.Identity)
+                {
+                    _matrix = null;
+                }
+                else
+                {
+                    Guard.IsFalse(this._skin.HasValue, _NOTRANSFORMMESSAGE);
+                    _matrix = value;
+                }
 
-            return animation.GetLocalTransform(this, time);
+                _scale = null;
+                _rotation = null;
+                _translation = null;
+            }
         }
 
         /// <summary>
@@ -149,6 +212,17 @@ namespace SharpGLTF.Schema2
             }
         }
 
+        #endregion
+
+        #region API - Transforms
+
+        public Transforms.AffineTransform GetLocalTransform(Animation animation, float time)
+        {
+            if (animation == null) return this.LocalTransform;
+
+            return animation.GetLocalTransform(this, time);
+        }
+
         public Matrix4x4 GetWorldMatrix(Animation animation, float time)
         {
             if (animation == null) return this.WorldMatrix;
@@ -164,105 +238,74 @@ namespace SharpGLTF.Schema2
         /// vertices to world space.
         /// </summary>
         /// <returns>A <see cref="Transforms.IGeometryTransform"/> object</returns>
-        public Transforms.IGeometryTransform GetMeshWorldTransform() { return GetMeshWorldTransform(null, 0); }
+        public Transforms.IGeometryTransform GetGeometryTransform() { return GetGeometryTransform(null, 0); }
 
         /// <summary>
-        /// Creates a <see cref="Transforms.IGeometryTransform"/> object, based on the current
+        /// Creates a <see cref="Transforms.IGeometryTransform"/> instance, based on the current
         /// transform state, and the given <see cref="Animation"/>, that can be used
         /// to transform the <see cref="Mesh"/> vertices to world space.
         /// </summary>
         /// <param name="animation">The <see cref="Animation"/> to use.</param>
         /// <param name="time">The time within <paramref name="animation"/>.</param>
         /// <returns>A <see cref="Transforms.IGeometryTransform"/> object</returns>
-        public Transforms.IGeometryTransform GetMeshWorldTransform(Animation animation, float time)
-        {
-            if (animation != null) Guard.MustShareLogicalParent(this, animation, nameof(animation));
-
-            var weights = animation == null ? Transforms.SparseWeight8.Create(this.MorphWeights) : animation.GetSparseMorphWeights(this, time);
-
-            if (this.Skin == null) return new Transforms.StaticTransform(this.GetWorldMatrix(animation, time), weights, false);
-
-            return new Transforms.SkinTransform
-                (
-                this.Skin.JointsCount,
-                idx => this.Skin.GetJoint(idx).Item2,
-                idx => this.Skin.GetJoint(idx).Item1.GetWorldMatrix(animation, time),
-                weights, false);
-        }
-
-        #endregion
-
-        #region properties - content
-
-        /// <summary>
-        /// Gets or sets the <see cref="Schema2.Camera"/> of this <see cref="Node"/>.
-        /// </summary>
-        public Camera Camera
+        public Transforms.IGeometryTransform GetGeometryTransform(Animation animation, float time)
         {
-            get => this._camera.HasValue ? this.LogicalParent.LogicalCameras[this._camera.Value] : null;
-            set
+            if (this.Skin == null)
             {
-                if (value == null) { this._camera = null; return; }
-
-                Guard.MustShareLogicalParent(this.LogicalParent, nameof(this.LogicalParent), value, nameof(value));
-
-                this._camera = value.LogicalIndex;
+                var statXform = new Transforms.StaticTransform();
+                UpdateGeometryTransform(statXform, animation, time);
+                return statXform;
             }
-        }
-
-        /// <summary>
-        /// Gets or sets the <see cref="Schema2.Mesh"/> of this <see cref="Node"/>.
-        /// </summary>
-        public Mesh Mesh
-        {
-            get => this._mesh.HasValue ? this.LogicalParent.LogicalMeshes[this._mesh.Value] : null;
-            set
+            else
             {
-                if (value == null) { this._mesh = null; return; }
-
-                Guard.MustShareLogicalParent(this.LogicalParent, nameof(this.LogicalParent), value, nameof(value));
-
-                this._mesh = value.LogicalIndex;
+                var skinXform = new Transforms.SkinTransform();
+                UpdateGeometryTransform(skinXform, animation, time);
+                return skinXform;
             }
         }
 
         /// <summary>
-        /// Gets or sets the <see cref="Schema2.Skin"/> of this <see cref="Node"/>.
+        /// Updates an existing instance of <see cref="Transforms.IGeometryTransform"/>.
         /// </summary>
-        public Skin Skin
+        /// <param name="transform">The <see cref="Transforms.IGeometryTransform"/> to update.</param>
+        /// <param name="animation">The <see cref="Animation"/> to use.</param>
+        /// <param name="time">The time within <paramref name="animation"/>.</param>
+        public void UpdateGeometryTransform(Transforms.IGeometryTransform transform, Animation animation, float time)
         {
-            get => this._skin.HasValue ? this.LogicalParent.LogicalSkins[this._skin.Value] : null;
-            set
-            {
-                if (value == null) { this._skin = null; return; }
-
-                Guard.MustShareLogicalParent(this.LogicalParent, nameof(this.LogicalParent), value, nameof(value));
+            Guard.NotNull(transform, nameof(transform));
+            if (animation != null) Guard.MustShareLogicalParent(this, animation, nameof(animation));
 
-                Guard.IsFalse(_matrix.HasValue, _NOTRANSFORMMESSAGE);
-                Guard.IsFalse(_scale.HasValue, _NOTRANSFORMMESSAGE);
-                Guard.IsFalse(_rotation.HasValue, _NOTRANSFORMMESSAGE);
-                Guard.IsFalse(_translation.HasValue, _NOTRANSFORMMESSAGE);
+            var weights = animation == null ? Transforms.SparseWeight8.Create(this.MorphWeights) : animation.GetSparseMorphWeights(this, time);
 
-                this._skin = value.LogicalIndex;
+            if (this.Skin == null)
+            {
+                if (transform is Transforms.StaticTransform statXform)
+                {
+                    statXform.Update(weights, false);
+                    statXform.Update(this.GetWorldMatrix(animation, time));
+                    return;
+                }
             }
-        }
-
-        /// <summary>
-        /// Gets or sets the Morph Weights of this <see cref="Node"/>.
-        /// </summary>
-        public IReadOnlyList<Single> MorphWeights
-        {
-            get => _weights.Count == 0 ? Mesh?.MorphWeights : _weights.Select(item => (float)item).ToList();
-            set
+            else
             {
-                _weights.Clear();
-                if (value != null) _weights.AddRange(value.Select(item => (Double)item));
+                if (transform is Transforms.SkinTransform skinXform)
+                {
+                    skinXform.Update(weights, false);
+                    skinXform.Update(
+                        this.Skin.JointsCount,
+                        idx => this.Skin.GetJoint(idx).Item2,
+                        idx => this.Skin.GetJoint(idx).Item1.GetWorldMatrix(animation, time)
+                        );
+                    return;
+                }
             }
+
+            throw new ArgumentException($"{nameof(transform)} type mismatch.", nameof(transform));
         }
 
         #endregion
 
-        #region API
+        #region API - hierarchy
 
         /// <summary>
         /// Creates a new <see cref="Node"/> instance,

+ 34 - 27
src/SharpGLTF.Core/Transforms/MeshTransforms.cs

@@ -59,12 +59,12 @@ namespace SharpGLTF.Transforms
 
         /// <summary>
         /// Represents a sparse collection of weights where:
-        /// - Index of value <see cref="_COMPLEMENT_INDEX"/> points to the Mesh master positions.
+        /// - Index of value <see cref="COMPLEMENT_INDEX"/> points to the Mesh master positions.
         /// - All other indices point to Mesh MorphTarget[index] positions.
         /// </summary>
         private SparseWeight8 _Weights;
 
-        private const int _COMPLEMENT_INDEX = 65536;
+        public const int COMPLEMENT_INDEX = 65536;
 
         /// <summary>
         /// True if morph targets represent absolute values.
@@ -76,6 +76,11 @@ namespace SharpGLTF.Transforms
 
         #region properties
 
+        /// <summary>
+        /// Gets the current morph weights to use for morph target blending. <see cref="COMPLEMENT_INDEX"/> represents the index for the base geometry.
+        /// </summary>
+        public SparseWeight8 MorphWeights => _Weights;
+
         /// <summary>
         /// Gets a value indicating whether morph target values are absolute, and not relative to the master value.
         /// </summary>
@@ -91,16 +96,16 @@ namespace SharpGLTF.Transforms
 
             if (morphWeights.IsWeightless)
             {
-                _Weights = SparseWeight8.Create((_COMPLEMENT_INDEX, 1));
+                _Weights = SparseWeight8.Create((COMPLEMENT_INDEX, 1));
                 return;
             }
 
-            _Weights = morphWeights.GetNormalizedWithComplement(_COMPLEMENT_INDEX);
+            _Weights = morphWeights.GetNormalizedWithComplement(COMPLEMENT_INDEX);
         }
 
         protected V3 MorphVectors(V3 value, V3[] morphTargets)
         {
-            if (_Weights.Index0 == _COMPLEMENT_INDEX && _Weights.Weight0 == 1) return value;
+            if (_Weights.Index0 == COMPLEMENT_INDEX && _Weights.Weight0 == 1) return value;
 
             if (morphTargets == null) return value;
 
@@ -110,7 +115,7 @@ namespace SharpGLTF.Transforms
             {
                 foreach (var pair in _Weights.GetNonZeroWeights())
                 {
-                    var val = pair.Item1 == _COMPLEMENT_INDEX ? value : morphTargets[pair.Item1];
+                    var val = pair.Item1 == COMPLEMENT_INDEX ? value : morphTargets[pair.Item1];
                     p += val * pair.Item2;
                 }
             }
@@ -118,7 +123,7 @@ namespace SharpGLTF.Transforms
             {
                 foreach (var pair in _Weights.GetNonZeroWeights())
                 {
-                    var val = pair.Item1 == _COMPLEMENT_INDEX ? value : value + morphTargets[pair.Item1];
+                    var val = pair.Item1 == COMPLEMENT_INDEX ? value : value + morphTargets[pair.Item1];
                     p += val * pair.Item2;
                 }
             }
@@ -128,7 +133,7 @@ namespace SharpGLTF.Transforms
 
         protected V4 MorphVectors(V4 value, V4[] morphTargets)
         {
-            if (_Weights.Index0 == _COMPLEMENT_INDEX && _Weights.Weight0 == 1) return value;
+            if (_Weights.Index0 == COMPLEMENT_INDEX && _Weights.Weight0 == 1) return value;
 
             if (morphTargets == null) return value;
 
@@ -138,7 +143,7 @@ namespace SharpGLTF.Transforms
             {
                 foreach (var pair in _Weights.GetNonZeroWeights())
                 {
-                    var val = pair.Item1 == _COMPLEMENT_INDEX ? value : morphTargets[pair.Item1];
+                    var val = pair.Item1 == COMPLEMENT_INDEX ? value : morphTargets[pair.Item1];
                     p += val * pair.Item2;
                 }
             }
@@ -146,7 +151,7 @@ namespace SharpGLTF.Transforms
             {
                 foreach (var pair in _Weights.GetNonZeroWeights())
                 {
-                    var val = pair.Item1 == _COMPLEMENT_INDEX ? value : value + morphTargets[pair.Item1];
+                    var val = pair.Item1 == COMPLEMENT_INDEX ? value : value + morphTargets[pair.Item1];
                     p += val * pair.Item2;
                 }
             }
@@ -171,23 +176,23 @@ namespace SharpGLTF.Transforms
             Update(TRANSFORM.Identity);
         }
 
-        public StaticTransform(TRANSFORM xform)
+        public StaticTransform(TRANSFORM worldMatrix)
         {
             Update(default, false);
-            Update(xform);
+            Update(worldMatrix);
         }
 
-        public StaticTransform(TRANSFORM xform, SparseWeight8 morphWeights, bool useAbsoluteMorphs)
+        public StaticTransform(TRANSFORM worldMatrix, SparseWeight8 morphWeights, bool useAbsoluteMorphs)
         {
             Update(morphWeights, useAbsoluteMorphs);
-            Update(xform);
+            Update(worldMatrix);
         }
 
         #endregion
 
         #region data
 
-        private TRANSFORM _Transform;
+        private TRANSFORM _WorldMatrix;
         private Boolean _Visible;
         private Boolean _FlipFaces;
 
@@ -199,23 +204,25 @@ namespace SharpGLTF.Transforms
 
         public Boolean FlipFaces => _FlipFaces;
 
+        public Matrix4x4 WorldMatrix => _WorldMatrix;
+
         #endregion
 
         #region API
 
-        public void Update(TRANSFORM xform)
+        public void Update(TRANSFORM worldMatrix)
         {
-            _Transform = xform;
+            _WorldMatrix = worldMatrix;
 
             // http://m-hikari.com/ija/ija-password-2009/ija-password5-8-2009/hajrizajIJA5-8-2009.pdf
 
             float determinant3x3 =
-                +(xform.M13 * xform.M21 * xform.M32)
-                + (xform.M11 * xform.M22 * xform.M33)
-                + (xform.M12 * xform.M23 * xform.M31)
-                - (xform.M12 * xform.M21 * xform.M33)
-                - (xform.M13 * xform.M22 * xform.M31)
-                - (xform.M11 * xform.M23 * xform.M32);
+                +(worldMatrix.M13 * worldMatrix.M21 * worldMatrix.M32)
+                + (worldMatrix.M11 * worldMatrix.M22 * worldMatrix.M33)
+                + (worldMatrix.M12 * worldMatrix.M23 * worldMatrix.M31)
+                - (worldMatrix.M12 * worldMatrix.M21 * worldMatrix.M33)
+                - (worldMatrix.M13 * worldMatrix.M22 * worldMatrix.M31)
+                - (worldMatrix.M11 * worldMatrix.M23 * worldMatrix.M32);
 
             _Visible = Math.Abs(determinant3x3) > float.Epsilon;
             _FlipFaces = determinant3x3 < 0;
@@ -225,21 +232,21 @@ namespace SharpGLTF.Transforms
         {
             position = MorphVectors(position, morphTargets);
 
-            return V3.Transform(position, _Transform);
+            return V3.Transform(position, _WorldMatrix);
         }
 
         public V3 TransformNormal(V3 normal, V3[] morphTargets, in SparseWeight8 skinWeights)
         {
             normal = MorphVectors(normal, morphTargets);
 
-            return V3.Normalize(V3.Transform(normal, _Transform));
+            return V3.Normalize(V3.Transform(normal, _WorldMatrix));
         }
 
         public V4 TransformTangent(V4 tangent, V3[] morphTargets, in SparseWeight8 skinWeights)
         {
             var n = MorphVectors(new V3(tangent.X, tangent.Y, tangent.Z), morphTargets);
 
-            n = V3.Normalize(V3.Transform(n, _Transform));
+            n = V3.Normalize(V3.Transform(n, _WorldMatrix));
 
             return new V4(n, tangent.W);
         }
@@ -278,7 +285,7 @@ namespace SharpGLTF.Transforms
         /// <summary>
         /// Gets the collection of the current, final matrices to use for skinning
         /// </summary>
-        public IReadOnlyList<TRANSFORM> SkinTransforms => _SkinTransforms;
+        public IReadOnlyList<TRANSFORM> SkinMatrices => _SkinTransforms;
 
         #endregion
 

+ 2 - 2
src/SharpGLTF.Toolkit/Schema2/SceneExtensions.cs

@@ -229,7 +229,7 @@ namespace SharpGLTF.Schema2
 
             if (node == null || mesh == null) return Enumerable.Empty<(IVertexBuilder, IVertexBuilder, IVertexBuilder, Material)>();
 
-            var xform = node.GetMeshWorldTransform(animation, time);
+            var xform = node.GetGeometryTransform(animation, time);
 
             return mesh.EvaluateTriangles(xform);
         }
@@ -269,7 +269,7 @@ namespace SharpGLTF.Schema2
 
             if (node == null || mesh == null) return Enumerable.Empty<(VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>, Material)>();
 
-            var xform = node.GetMeshWorldTransform(animation, time);
+            var xform = node.GetGeometryTransform(animation, time);
 
             return mesh.EvaluateTriangles<TvG, TvM, VertexEmpty>(xform);
         }

+ 1 - 1
tests/SharpGLTF.Tests/Schema2/LoadAndSave/LoadSampleTests.cs

@@ -287,7 +287,7 @@ namespace SharpGLTF.Schema2.LoadAndSave
 
             for (float t = 0; t < 5; t+=0.25f)
             {
-                var nodexform = node.GetMeshWorldTransform(anim, t);
+                var nodexform = node.GetGeometryTransform(anim, t);
 
                 TestContext.WriteLine($"Animation at {t}");