|
|
@@ -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,
|