MorphTargetBuilder.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Numerics;
  5. using System.Text;
  6. using SharpGLTF.Geometry.VertexTypes;
  7. namespace SharpGLTF.Geometry
  8. {
  9. public interface IPrimitiveMorphTargetReader
  10. {
  11. /// <summary>
  12. /// Gets the collection of vertex indices that have morph target deltas.
  13. /// </summary>
  14. /// <returns>A collection of vertex indices.</returns>
  15. IReadOnlyCollection<int> GetTargetIndices();
  16. /// <summary>
  17. /// Gets the vertex for the given <paramref name="vertexIndex"/> morphed by the current morph target (if any).
  18. /// </summary>
  19. /// <param name="vertexIndex">The index of the vertex.</param>
  20. /// <returns>If the given index has a morphed vertex, it will return it, else ir will return the base vertex.</returns>
  21. IVertexGeometry GetVertex(int vertexIndex);
  22. /// <summary>
  23. /// Gets the <see cref="VertexGeometryDelta"/> of a given vertex for a given morph target.
  24. /// </summary>
  25. /// <param name="vertexIndex">The index of the vertex.</param>
  26. /// <returns>A Vertex delta (Morphed vertex minus base vertex).</returns>
  27. VertexGeometryDelta GetVertexDelta(int vertexIndex);
  28. }
  29. sealed class PrimitiveMorphTargetBuilder<TvG> : IPrimitiveMorphTargetReader
  30. where TvG : struct, IVertexGeometry
  31. {
  32. #region lifecycle
  33. internal PrimitiveMorphTargetBuilder(Func<int, TvG> baseVertexFunc)
  34. {
  35. this._BaseVertexFunc = baseVertexFunc;
  36. this._MorphVertices = new Dictionary<int, TvG>();
  37. }
  38. internal PrimitiveMorphTargetBuilder(Func<int, TvG> baseVertexFunc, PrimitiveMorphTargetBuilder<TvG> other)
  39. {
  40. this._BaseVertexFunc = baseVertexFunc;
  41. this._MorphVertices = new Dictionary<int, TvG>(other._MorphVertices);
  42. }
  43. #endregion
  44. #region data
  45. private readonly Func<int, TvG> _BaseVertexFunc;
  46. private readonly Dictionary<int, TvG> _MorphVertices;
  47. #endregion
  48. #region API
  49. public IReadOnlyCollection<int> GetTargetIndices()
  50. {
  51. return _MorphVertices.Keys;
  52. }
  53. public VertexGeometryDelta GetVertexDelta(int vertexIndex)
  54. {
  55. if (_MorphVertices.TryGetValue(vertexIndex, out TvG value))
  56. {
  57. return value.Subtract(_BaseVertexFunc(vertexIndex));
  58. }
  59. return default;
  60. }
  61. public void SetVertexDelta(int vertexIndex, VertexGeometryDelta value)
  62. {
  63. if (object.Equals(value, default(VertexGeometryDelta)))
  64. {
  65. _RemoveVertex(vertexIndex);
  66. return;
  67. }
  68. var vertex = _BaseVertexFunc(vertexIndex);
  69. vertex.Add(value);
  70. _SetVertex(vertexIndex, vertex);
  71. }
  72. IVertexGeometry IPrimitiveMorphTargetReader.GetVertex(int vertexIndex)
  73. {
  74. return _MorphVertices.TryGetValue(vertexIndex, out TvG value) ? value : _BaseVertexFunc(vertexIndex);
  75. }
  76. public TvG GetVertex(int vertexIndex)
  77. {
  78. return _MorphVertices.TryGetValue(vertexIndex, out TvG value) ? value : _BaseVertexFunc(vertexIndex);
  79. }
  80. public void SetVertex(int vertexIndex, TvG value)
  81. {
  82. if (object.Equals(value, _BaseVertexFunc(vertexIndex)))
  83. {
  84. _RemoveVertex(vertexIndex);
  85. return;
  86. }
  87. _SetVertex(vertexIndex, value);
  88. }
  89. private void _SetVertex(int vertexIndex, TvG value)
  90. {
  91. _MorphVertices[vertexIndex] = value;
  92. }
  93. private void _RemoveVertex(int vertexIndex)
  94. {
  95. _MorphVertices.Remove(vertexIndex);
  96. }
  97. #endregion
  98. #region internals
  99. internal void TransformVertices(Func<TvG, TvG> vertexFunc)
  100. {
  101. foreach (var vidx in _MorphVertices.Keys)
  102. {
  103. var g = GetVertex(vidx);
  104. g = vertexFunc(g);
  105. SetVertex(vidx, g);
  106. }
  107. }
  108. internal void SetMorphTargets(IPrimitiveMorphTargetReader other, IReadOnlyDictionary<int, int> vertexMap, Func<IVertexGeometry, TvG> vertexFunc)
  109. {
  110. Guard.NotNull(vertexFunc, nameof(vertexFunc));
  111. var indices = other.GetTargetIndices();
  112. foreach (var srcVidx in indices)
  113. {
  114. var g = vertexFunc(other.GetVertex(srcVidx));
  115. var dstVidx = srcVidx;
  116. if (vertexMap != null)
  117. {
  118. if (!vertexMap.TryGetValue(srcVidx, out dstVidx)) dstVidx = -1;
  119. }
  120. if (dstVidx >= 0) this.SetVertex(dstVidx, g);
  121. }
  122. }
  123. #endregion
  124. }
  125. public interface IMorphTargetBuilder
  126. {
  127. IReadOnlyCollection<Vector3> Positions { get; }
  128. IReadOnlyCollection<IVertexGeometry> Vertices { get; }
  129. IReadOnlyList<IVertexGeometry> GetVertices(Vector3 position);
  130. void SetVertex(IVertexGeometry meshVertex, IVertexGeometry morphVertex);
  131. void SetVertexDelta(Vector3 key, VertexGeometryDelta delta);
  132. void SetVertexDelta(IVertexGeometry meshVertex, VertexGeometryDelta delta);
  133. }
  134. /// <summary>
  135. /// Utility class to edit the Morph targets of a mesh.
  136. /// </summary>
  137. public sealed class MorphTargetBuilder<TMaterial, TvG, TvS, TvM> : IMorphTargetBuilder
  138. where TvG : struct, IVertexGeometry
  139. where TvM : struct, IVertexMaterial
  140. where TvS : struct, IVertexSkinning
  141. {
  142. #region lifecycle
  143. internal MorphTargetBuilder(MeshBuilder<TMaterial, TvG, TvM, TvS> mesh, int morphTargetIndex)
  144. {
  145. _Mesh = mesh;
  146. _MorphTargetIndex = morphTargetIndex;
  147. foreach (var prim in _Mesh.Primitives)
  148. {
  149. for (int vidx = 0; vidx < prim.Vertices.Count; ++vidx)
  150. {
  151. var key = prim.Vertices[vidx].Geometry;
  152. if (!_Vertices.TryGetValue(key, out List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)> val))
  153. {
  154. _Vertices[key] = val = new List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)>();
  155. }
  156. val.Add((prim, vidx));
  157. if (!_Positions.TryGetValue(key.GetPosition(), out List<TvG> geos))
  158. {
  159. _Positions[key.GetPosition()] = geos = new List<TvG>();
  160. }
  161. geos.Add(key);
  162. }
  163. }
  164. }
  165. #endregion
  166. #region data
  167. private readonly MeshBuilder<TMaterial, TvG, TvM, TvS> _Mesh;
  168. private readonly int _MorphTargetIndex;
  169. private readonly Dictionary<TvG, List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)>> _Vertices = new Dictionary<TvG, List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)>>();
  170. private readonly Dictionary<Vector3, List<TvG>> _Positions = new Dictionary<Vector3, List<TvG>>();
  171. #endregion
  172. #region properties
  173. public IReadOnlyCollection<Vector3> Positions => _Positions.Keys;
  174. public IReadOnlyCollection<TvG> Vertices => _Vertices.Keys;
  175. IReadOnlyCollection<IVertexGeometry> IMorphTargetBuilder.Vertices => (IReadOnlyList<IVertexGeometry>)(IReadOnlyCollection<TvG>)_Vertices.Keys;
  176. #endregion
  177. #region API
  178. public IReadOnlyList<TvG> GetVertices(Vector3 position)
  179. {
  180. return _Positions.TryGetValue(position, out List<TvG> geos) ? (IReadOnlyList<TvG>)geos : Array.Empty<TvG>();
  181. }
  182. IReadOnlyList<IVertexGeometry> IMorphTargetBuilder.GetVertices(Vector3 position)
  183. {
  184. return _Positions.TryGetValue(position, out List<TvG> geos) ? (IReadOnlyList<IVertexGeometry>)geos : Array.Empty<IVertexGeometry>();
  185. }
  186. public void SetVertexDelta(Vector3 key, VertexGeometryDelta delta)
  187. {
  188. if (_Positions.TryGetValue(key, out List<TvG> geos))
  189. {
  190. foreach (var g in geos) SetVertexDelta(g, delta);
  191. }
  192. }
  193. public void SetVertex(TvG meshVertex, TvG morphVertex)
  194. {
  195. if (_Vertices.TryGetValue(meshVertex, out List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)> val))
  196. {
  197. foreach (var entry in val)
  198. {
  199. entry.Item1
  200. ._UseMorphTarget(_MorphTargetIndex)
  201. .SetVertex(entry.Item2, morphVertex);
  202. }
  203. }
  204. }
  205. void IMorphTargetBuilder.SetVertex(IVertexGeometry meshVertex, IVertexGeometry morphVertex)
  206. {
  207. SetVertex(meshVertex.ConvertToGeometry<TvG>(), morphVertex.ConvertToGeometry<TvG>());
  208. }
  209. public void SetVertexDelta(TvG meshVertex, VertexGeometryDelta delta)
  210. {
  211. if (_Vertices.TryGetValue(meshVertex, out List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)> val))
  212. {
  213. foreach (var entry in val)
  214. {
  215. entry.Item1
  216. ._UseMorphTarget(_MorphTargetIndex)
  217. .SetVertexDelta(entry.Item2, delta);
  218. }
  219. }
  220. }
  221. void IMorphTargetBuilder.SetVertexDelta(IVertexGeometry meshVertex, VertexGeometryDelta delta)
  222. {
  223. SetVertexDelta(meshVertex.ConvertToGeometry<TvG>(), delta);
  224. }
  225. #endregion
  226. }
  227. }