SceneInstance.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using SharpGLTF.Transforms;
  7. using XFORM = System.Numerics.Matrix4x4;
  8. namespace SharpGLTF.Runtime
  9. {
  10. /// <summary>
  11. /// Represents a specific and independent state of a <see cref="SceneTemplate"/>.
  12. /// </summary>
  13. public sealed class SceneInstance
  14. {
  15. #region lifecycle
  16. internal SceneInstance(NodeTemplate[] nodeTemplates, DrawableTemplate[] drawables, Collections.NamedList<float> tracks)
  17. {
  18. _AnimationTracks = tracks;
  19. _NodeTemplates = nodeTemplates;
  20. _NodeInstances = new NodeInstance[_NodeTemplates.Length];
  21. for (var i = 0; i < _NodeInstances.Length; ++i)
  22. {
  23. var n = _NodeTemplates[i];
  24. var pidx = _NodeTemplates[i].ParentIndex;
  25. if (pidx >= i) throw new ArgumentException("invalid parent index", nameof(nodeTemplates));
  26. var p = pidx < 0 ? null : _NodeInstances[pidx];
  27. _NodeInstances[i] = new NodeInstance(n, p);
  28. }
  29. _DrawableReferences = drawables;
  30. _DrawableTransforms = new IGeometryTransform[_DrawableReferences.Length];
  31. for (int i = 0; i < _DrawableTransforms.Length; ++i)
  32. {
  33. _DrawableTransforms[i] = _DrawableReferences[i].CreateGeometryTransform();
  34. }
  35. }
  36. #endregion
  37. #region data
  38. private readonly NodeTemplate[] _NodeTemplates;
  39. private readonly NodeInstance[] _NodeInstances;
  40. private readonly DrawableTemplate[] _DrawableReferences;
  41. private readonly IGeometryTransform[] _DrawableTransforms;
  42. private readonly Collections.NamedList<float> _AnimationTracks;
  43. #endregion
  44. #region properties
  45. /// <summary>
  46. /// Gets a list of all the <see cref="NodeInstance"/> nodes used by this <see cref="SceneInstance"/>.
  47. /// </summary>
  48. public IReadOnlyList<NodeInstance> LogicalNodes => _NodeInstances;
  49. /// <summary>
  50. /// Gets all the <see cref="NodeInstance"/> roots used by this <see cref="SceneInstance"/>.
  51. /// </summary>
  52. public IEnumerable<NodeInstance> VisualNodes => _NodeInstances.Where(item => item.VisualParent == null);
  53. /// <summary>
  54. /// Gets all the names of the animations tracks.
  55. /// </summary>
  56. public IEnumerable<String> AnimationTracks => _AnimationTracks.Names;
  57. /// <summary>
  58. /// Gets the number of drawable references.
  59. /// </summary>
  60. [Obsolete("Use DrawableInstancesCount")]
  61. public int DrawableReferencesCount => _DrawableTransforms.Length;
  62. /// <summary>
  63. /// Gets the number of drawable instances.
  64. /// </summary>
  65. public int DrawableInstancesCount => _DrawableTransforms.Length;
  66. /// <summary>
  67. /// Gets a collection of drawable references, where:
  68. /// <list type="bullet">
  69. /// <item>
  70. /// <term>MeshIndex</term>
  71. /// <description>The logical Index of a <see cref="Schema2.Mesh"/> in <see cref="Schema2.ModelRoot.LogicalMeshes"/>.</description>
  72. /// </item>
  73. /// <item>
  74. /// <term>Transform</term>
  75. /// <description>An <see cref="IGeometryTransform"/> that can be used to transform the <see cref="Schema2.Mesh"/> into world space.</description>
  76. /// </item>
  77. /// </list>
  78. /// </summary>
  79. [Obsolete("Use DrawableInstances.")]
  80. public IEnumerable<(int MeshIndex, IGeometryTransform Transform)> DrawableReferences
  81. {
  82. get
  83. {
  84. for (int i = 0; i < _DrawableTransforms.Length; ++i)
  85. {
  86. yield return GetDrawableReference(i);
  87. }
  88. }
  89. }
  90. public IEnumerable<DrawableInstance> DrawableInstances
  91. {
  92. get
  93. {
  94. for (int i = 0; i < _DrawableTransforms.Length; ++i)
  95. {
  96. yield return GetDrawableInstance(i);
  97. }
  98. }
  99. }
  100. #endregion
  101. #region API
  102. public void SetLocalMatrix(string name, XFORM localMatrix)
  103. {
  104. var n = LogicalNodes.FirstOrDefault(item => item.Name == name);
  105. if (n == null) return;
  106. n.LocalMatrix = localMatrix;
  107. }
  108. public void SetWorldMatrix(string name, XFORM worldMatrix)
  109. {
  110. var n = LogicalNodes.FirstOrDefault(item => item.Name == name);
  111. if (n == null) return;
  112. n.WorldMatrix = worldMatrix;
  113. }
  114. public void SetPoseTransforms()
  115. {
  116. foreach (var n in _NodeInstances) n.SetPoseTransform();
  117. }
  118. public float GetAnimationDuration(int trackLogicalIndex)
  119. {
  120. if (trackLogicalIndex < 0) return 0;
  121. if (trackLogicalIndex >= _AnimationTracks.Count) return 0;
  122. return _AnimationTracks[trackLogicalIndex];
  123. }
  124. public float GetAnimationDuration(string trackName)
  125. {
  126. return GetAnimationDuration(_AnimationTracks.IndexOf(trackName));
  127. }
  128. public void SetAnimationFrame(int trackLogicalIndex, float time, bool looped = true)
  129. {
  130. if (looped)
  131. {
  132. var duration = GetAnimationDuration(trackLogicalIndex);
  133. if (duration > 0) time = time % duration;
  134. }
  135. foreach (var n in _NodeInstances) n.SetAnimationFrame(trackLogicalIndex, time);
  136. }
  137. public void SetAnimationFrame(string trackName, float time, bool looped = true)
  138. {
  139. SetAnimationFrame(_AnimationTracks.IndexOf(trackName), time, looped);
  140. }
  141. public void SetAnimationFrame(params (int TrackIdx, float Time, float Weight)[] blended)
  142. {
  143. SetAnimationFrame(_NodeInstances, blended);
  144. }
  145. public static void SetAnimationFrame(IEnumerable<NodeInstance> nodes, params (int TrackIdx, float Time, float Weight)[] blended)
  146. {
  147. Guard.NotNull(nodes, nameof(nodes));
  148. Span<int> tracks = stackalloc int[blended.Length];
  149. Span<float> times = stackalloc float[blended.Length];
  150. Span<float> weights = stackalloc float[blended.Length];
  151. float w = blended.Sum(item => item.Weight);
  152. w = w == 0 ? 1 : 1 / w;
  153. for (int i = 0; i < blended.Length; ++i)
  154. {
  155. tracks[i] = blended[i].TrackIdx;
  156. times[i] = blended[i].Time;
  157. weights[i] = blended[i].Weight * w;
  158. }
  159. foreach (var n in nodes) n.SetAnimationFrame(tracks, times, weights);
  160. }
  161. /// <summary>
  162. /// Gets a drawable reference pair, where:
  163. /// - MeshIndex is the logical Index of a <see cref="Schema2.Mesh"/> in <see cref="Schema2.ModelRoot.LogicalMeshes"/>.
  164. /// - Transform is an <see cref="IGeometryTransform"/> that can be used to transform the <see cref="Schema2.Mesh"/> into world space.
  165. /// </summary>
  166. /// <param name="index">The index of the drawable reference, from 0 to <see cref="DrawableReferencesCount"/></param>
  167. /// <returns>A drawable reference</returns>
  168. [Obsolete("Use GetDrawableInstance")]
  169. public (int MeshIndex, IGeometryTransform Transform) GetDrawableReference(int index)
  170. {
  171. var dref = _DrawableReferences[index];
  172. dref.UpdateGeometryTransform(_DrawableTransforms[index], _NodeInstances);
  173. return (dref.LogicalMeshIndex, _DrawableTransforms[index]);
  174. }
  175. /// <summary>
  176. /// Gets a <see cref="DrawableInstance"/> object, where:
  177. /// - Name is the name of this drawable instance. Originally, it was the name of <see cref="Schema2.Node"/>.
  178. /// - MeshIndex is the logical Index of a <see cref="Schema2.Mesh"/> in <see cref="Schema2.ModelRoot.LogicalMeshes"/>.
  179. /// - Transform is an <see cref="IGeometryTransform"/> that can be used to transform the <see cref="Schema2.Mesh"/> into world space.
  180. /// </summary>
  181. /// <param name="index">The index of the drawable reference, from 0 to <see cref="DrawableInstancesCount"/></param>
  182. /// <returns><see cref="DrawableInstance"/> object.</returns>
  183. public DrawableInstance GetDrawableInstance(int index)
  184. {
  185. var dref = _DrawableReferences[index];
  186. dref.UpdateGeometryTransform(_DrawableTransforms[index], _NodeInstances);
  187. return new DrawableInstance(dref, _DrawableTransforms[index]);
  188. }
  189. #endregion
  190. }
  191. }