|
|
@@ -7,294 +7,6 @@ using System.Threading.Tasks;
|
|
|
|
|
|
namespace SharpGLTF.Runtime
|
|
|
{
|
|
|
- /// <summary>
|
|
|
- /// Defines a hierarchical transform node of a scene graph tree.
|
|
|
- /// </summary>
|
|
|
- [System.Diagnostics.DebuggerDisplay("[{LogicalNodeIndex}] {Name}")]
|
|
|
- class NodeTemplate
|
|
|
- {
|
|
|
- #region lifecycle
|
|
|
-
|
|
|
- internal NodeTemplate(Schema2.Node srcNode, int parentIdx, int[] childIndices, bool isolateMemory)
|
|
|
- {
|
|
|
- _LogicalSourceIndex = srcNode.LogicalIndex;
|
|
|
-
|
|
|
- _ParentIndex = parentIdx;
|
|
|
- _ChildIndices = childIndices;
|
|
|
-
|
|
|
- Name = srcNode.Name;
|
|
|
-
|
|
|
- _LocalMatrix = srcNode.LocalMatrix;
|
|
|
- _LocalTransform = srcNode.LocalTransform;
|
|
|
-
|
|
|
- _Scale = new AnimatableProperty<Vector3>(_LocalTransform.Scale);
|
|
|
- _Rotation = new AnimatableProperty<Quaternion>(_LocalTransform.Rotation);
|
|
|
- _Translation = new AnimatableProperty<Vector3>(_LocalTransform.Translation);
|
|
|
-
|
|
|
- var mw = Transforms.SparseWeight8.Create(srcNode.MorphWeights);
|
|
|
- _Morphing = new AnimatableProperty<Transforms.SparseWeight8>(mw);
|
|
|
-
|
|
|
- foreach (var anim in srcNode.LogicalParent.LogicalAnimations)
|
|
|
- {
|
|
|
- var index = anim.LogicalIndex;
|
|
|
- var name = anim.Name;
|
|
|
-
|
|
|
- var scaAnim = anim.FindScaleSampler(srcNode)?.CreateCurveSampler(isolateMemory);
|
|
|
- if (scaAnim != null) _Scale.AddCurve(index, name, scaAnim);
|
|
|
-
|
|
|
- var rotAnim = anim.FindRotationSampler(srcNode)?.CreateCurveSampler(isolateMemory);
|
|
|
- if (rotAnim != null) _Rotation.AddCurve(index, name, rotAnim);
|
|
|
-
|
|
|
- var traAnim = anim.FindTranslationSampler(srcNode)?.CreateCurveSampler(isolateMemory);
|
|
|
- if (traAnim != null) _Translation.AddCurve(index, name, traAnim);
|
|
|
-
|
|
|
- var mrpAnim = anim.FindSparseMorphSampler(srcNode)?.CreateCurveSampler(isolateMemory);
|
|
|
- if (mrpAnim != null) _Morphing.AddCurve(index, name, mrpAnim);
|
|
|
- }
|
|
|
-
|
|
|
- _UsePrecomputed = !(_Scale.IsAnimated | _Rotation.IsAnimated | _Translation.IsAnimated);
|
|
|
-
|
|
|
- if (_UsePrecomputed)
|
|
|
- {
|
|
|
- _Scale = null;
|
|
|
- _Rotation = null;
|
|
|
- _Translation = null;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- #endregion
|
|
|
-
|
|
|
- #region data
|
|
|
-
|
|
|
- private readonly int _LogicalSourceIndex;
|
|
|
-
|
|
|
- private readonly int _ParentIndex;
|
|
|
- private readonly int[] _ChildIndices;
|
|
|
-
|
|
|
- private readonly bool _UsePrecomputed;
|
|
|
- private readonly Matrix4x4 _LocalMatrix;
|
|
|
- private readonly Transforms.AffineTransform _LocalTransform;
|
|
|
-
|
|
|
- private readonly AnimatableProperty<Vector3> _Scale;
|
|
|
- private readonly AnimatableProperty<Quaternion> _Rotation;
|
|
|
- private readonly AnimatableProperty<Vector3> _Translation;
|
|
|
- private readonly AnimatableProperty<Transforms.SparseWeight8> _Morphing;
|
|
|
-
|
|
|
- #endregion
|
|
|
-
|
|
|
- #region properties
|
|
|
-
|
|
|
- public string Name { get; set; }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Gets the index of the source <see cref="Schema2.Node"/> in <see cref="Schema2.ModelRoot.LogicalNodes"/>
|
|
|
- /// </summary>
|
|
|
- public int LogicalNodeIndex => _LogicalSourceIndex;
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Gets the index of the parent <see cref="NodeTemplate"/> in <see cref="SceneTemplate._NodeTemplates"/>
|
|
|
- /// </summary>
|
|
|
- public int ParentIndex => _ParentIndex;
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Gets the list of indices of the children <see cref="NodeTemplate"/> in <see cref="SceneTemplate._NodeTemplates"/>
|
|
|
- /// </summary>
|
|
|
- public IReadOnlyList<int> ChildIndices => _ChildIndices;
|
|
|
-
|
|
|
- public Matrix4x4 LocalMatrix => _LocalMatrix;
|
|
|
-
|
|
|
- #endregion
|
|
|
-
|
|
|
- #region API
|
|
|
-
|
|
|
- public Transforms.SparseWeight8 GetMorphWeights(int trackLogicalIndex, float time)
|
|
|
- {
|
|
|
- if (trackLogicalIndex < 0) return _Morphing.Value;
|
|
|
-
|
|
|
- return _Morphing.GetValueAt(trackLogicalIndex, time);
|
|
|
- }
|
|
|
-
|
|
|
- public Transforms.SparseWeight8 GetMorphWeights(ReadOnlySpan<int> track, ReadOnlySpan<float> time, ReadOnlySpan<float> weight)
|
|
|
- {
|
|
|
- if (!_Morphing.IsAnimated) return _Morphing.Value;
|
|
|
-
|
|
|
- Span<Transforms.SparseWeight8> xforms = stackalloc Transforms.SparseWeight8[track.Length];
|
|
|
-
|
|
|
- for (int i = 0; i < xforms.Length; ++i)
|
|
|
- {
|
|
|
- xforms[i] = GetMorphWeights(track[i], time[i]);
|
|
|
- }
|
|
|
-
|
|
|
- return Transforms.SparseWeight8.Blend(xforms, weight);
|
|
|
- }
|
|
|
-
|
|
|
- public Transforms.AffineTransform GetLocalTransform(int trackLogicalIndex, float time)
|
|
|
- {
|
|
|
- if (_UsePrecomputed || trackLogicalIndex < 0) return _LocalTransform;
|
|
|
-
|
|
|
- var s = _Scale?.GetValueAt(trackLogicalIndex, time);
|
|
|
- var r = _Rotation?.GetValueAt(trackLogicalIndex, time);
|
|
|
- var t = _Translation?.GetValueAt(trackLogicalIndex, time);
|
|
|
-
|
|
|
- return Transforms.AffineTransform.Create(s, r, t);
|
|
|
- }
|
|
|
-
|
|
|
- public Transforms.AffineTransform GetLocalTransform(ReadOnlySpan<int> track, ReadOnlySpan<float> time, ReadOnlySpan<float> weight)
|
|
|
- {
|
|
|
- if (_UsePrecomputed) return _LocalTransform;
|
|
|
-
|
|
|
- Span<Transforms.AffineTransform> xforms = stackalloc Transforms.AffineTransform[track.Length];
|
|
|
-
|
|
|
- for (int i = 0; i < xforms.Length; ++i)
|
|
|
- {
|
|
|
- xforms[i] = GetLocalTransform(track[i], time[i]);
|
|
|
- }
|
|
|
-
|
|
|
- return Transforms.AffineTransform.Blend(xforms, weight);
|
|
|
- }
|
|
|
-
|
|
|
- public Matrix4x4 GetLocalMatrix(int trackLogicalIndex, float time)
|
|
|
- {
|
|
|
- if (_UsePrecomputed || trackLogicalIndex < 0) return _LocalMatrix;
|
|
|
-
|
|
|
- return GetLocalTransform(trackLogicalIndex, time).Matrix;
|
|
|
- }
|
|
|
-
|
|
|
- public Matrix4x4 GetLocalMatrix(ReadOnlySpan<int> track, ReadOnlySpan<float> time, ReadOnlySpan<float> weight)
|
|
|
- {
|
|
|
- if (_UsePrecomputed) return _LocalMatrix;
|
|
|
-
|
|
|
- return GetLocalTransform(track, time, weight).Matrix;
|
|
|
- }
|
|
|
-
|
|
|
- #endregion
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Defines a reference to a drawable mesh
|
|
|
- /// </summary>
|
|
|
- abstract class DrawableReference
|
|
|
- {
|
|
|
- #region lifecycle
|
|
|
-
|
|
|
- protected DrawableReference(Schema2.Node node)
|
|
|
- {
|
|
|
- _LogicalMeshIndex = node.Mesh.LogicalIndex;
|
|
|
- }
|
|
|
-
|
|
|
- #endregion
|
|
|
-
|
|
|
- #region data
|
|
|
-
|
|
|
- private readonly int _LogicalMeshIndex;
|
|
|
-
|
|
|
- #endregion
|
|
|
-
|
|
|
- #region properties
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Gets the index of a <see cref="Schema2.Mesh"/> in <see cref="Schema2.ModelRoot.LogicalMeshes"/>
|
|
|
- /// </summary>
|
|
|
- public int LogicalMeshIndex => _LogicalMeshIndex;
|
|
|
-
|
|
|
- #endregion
|
|
|
-
|
|
|
- #region API
|
|
|
-
|
|
|
- public abstract Transforms.IGeometryTransform CreateGeometryTransform();
|
|
|
-
|
|
|
- public abstract void UpdateGeometryTransform(Transforms.IGeometryTransform geoxform, IReadOnlyList<NodeInstance> instances);
|
|
|
-
|
|
|
- #endregion
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Defines a reference to a drawable rigid mesh
|
|
|
- /// </summary>
|
|
|
- sealed class RigidDrawableReference : DrawableReference
|
|
|
- {
|
|
|
- #region lifecycle
|
|
|
-
|
|
|
- internal RigidDrawableReference(Schema2.Node node, Func<Schema2.Node, int> indexFunc)
|
|
|
- : base(node)
|
|
|
- {
|
|
|
- _NodeIndex = indexFunc(node);
|
|
|
- }
|
|
|
-
|
|
|
- #endregion
|
|
|
-
|
|
|
- #region data
|
|
|
-
|
|
|
- private readonly int _NodeIndex;
|
|
|
-
|
|
|
- #endregion
|
|
|
-
|
|
|
- #region API
|
|
|
-
|
|
|
- public override Transforms.IGeometryTransform CreateGeometryTransform() { return new Transforms.RigidTransform(); }
|
|
|
-
|
|
|
- public override void UpdateGeometryTransform(Transforms.IGeometryTransform rigidTransform, IReadOnlyList<NodeInstance> instances)
|
|
|
- {
|
|
|
- var node = instances[_NodeIndex];
|
|
|
-
|
|
|
- var statxform = (Transforms.RigidTransform)rigidTransform;
|
|
|
- statxform.Update(node.WorldMatrix);
|
|
|
- statxform.Update(node.MorphWeights, false);
|
|
|
- }
|
|
|
-
|
|
|
- #endregion
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Defines a reference to a drawable skinned mesh
|
|
|
- /// </summary>
|
|
|
- sealed class SkinnedDrawableReference : DrawableReference
|
|
|
- {
|
|
|
- #region lifecycle
|
|
|
-
|
|
|
- internal SkinnedDrawableReference(Schema2.Node node, Func<Schema2.Node, int> indexFunc)
|
|
|
- : base(node)
|
|
|
- {
|
|
|
- var skin = node.Skin;
|
|
|
-
|
|
|
- _MorphNodeIndex = indexFunc(node);
|
|
|
-
|
|
|
- _JointsNodeIndices = new int[skin.JointsCount];
|
|
|
- _BindMatrices = new Matrix4x4[skin.JointsCount];
|
|
|
-
|
|
|
- for (int i = 0; i < _JointsNodeIndices.Length; ++i)
|
|
|
- {
|
|
|
- var (j, ibm) = skin.GetJoint(i);
|
|
|
-
|
|
|
- _JointsNodeIndices[i] = indexFunc(j);
|
|
|
- _BindMatrices[i] = ibm;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- #endregion
|
|
|
-
|
|
|
- #region data
|
|
|
-
|
|
|
- private readonly int _MorphNodeIndex;
|
|
|
- private readonly int[] _JointsNodeIndices;
|
|
|
- private readonly Matrix4x4[] _BindMatrices;
|
|
|
-
|
|
|
- #endregion
|
|
|
-
|
|
|
- #region API
|
|
|
-
|
|
|
- public override Transforms.IGeometryTransform CreateGeometryTransform() { return new Transforms.SkinnedTransform(); }
|
|
|
-
|
|
|
- public override void UpdateGeometryTransform(Transforms.IGeometryTransform skinnedTransform, IReadOnlyList<NodeInstance> instances)
|
|
|
- {
|
|
|
- var skinxform = (Transforms.SkinnedTransform)skinnedTransform;
|
|
|
- skinxform.Update(_JointsNodeIndices.Length, idx => _BindMatrices[idx], idx => instances[_JointsNodeIndices[idx]].WorldMatrix);
|
|
|
- skinxform.Update(instances[_MorphNodeIndex].MorphWeights, false);
|
|
|
- }
|
|
|
-
|
|
|
- #endregion
|
|
|
- }
|
|
|
-
|
|
|
/// <summary>
|
|
|
/// Defines a templatized representation of a <see cref="Schema2.Scene"/> that can be used
|
|
|
/// to create <see cref="SceneInstance"/>, which can help render a scene on a client application.
|