MorphTargetBuilder.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  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. IVertexBuilder 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. VertexBuilder<VertexGeometryDelta, VertexMaterialDelta, VertexEmpty> GetVertexDelta(int vertexIndex);
  28. }
  29. /// <summary>
  30. /// Represents the vertex deltas of a specific morph target.
  31. /// <see cref="PrimitiveBuilder{TMaterial, TvG, TvM, TvS}._UseMorphTarget(int)"/>
  32. /// </summary>
  33. /// <typeparam name="TvG">The vertex fragment type with Position, Normal and Tangent.</typeparam>
  34. class PrimitiveMorphTargetBuilder<TvG, TvM> : IPrimitiveMorphTargetReader
  35. where TvG : struct, IVertexGeometry
  36. where TvM : struct, IVertexMaterial
  37. {
  38. #region lifecycle
  39. internal PrimitiveMorphTargetBuilder(Func<int, VertexBuilder<TvG, TvM, VertexEmpty>> baseVertexFunc)
  40. {
  41. this._BaseVertexFunc = baseVertexFunc;
  42. this._MorphVertices = new Dictionary<int, VertexBuilder<TvG, TvM, VertexEmpty>>();
  43. }
  44. internal PrimitiveMorphTargetBuilder(Func<int, VertexBuilder<TvG, TvM, VertexEmpty>> baseVertexFunc, PrimitiveMorphTargetBuilder<TvG, TvM> other)
  45. {
  46. this._BaseVertexFunc = baseVertexFunc;
  47. this._MorphVertices = new Dictionary<int, VertexBuilder<TvG, TvM, VertexEmpty>>(other._MorphVertices);
  48. }
  49. #endregion
  50. #region data
  51. private readonly Func<int, VertexBuilder<TvG, TvM, VertexEmpty>> _BaseVertexFunc;
  52. private readonly Dictionary<int, VertexBuilder<TvG, TvM, VertexEmpty>> _MorphVertices;
  53. #endregion
  54. #region API
  55. public IReadOnlyCollection<int> GetTargetIndices()
  56. {
  57. return _MorphVertices.Keys;
  58. }
  59. public VertexBuilder<VertexGeometryDelta, VertexMaterialDelta, VertexEmpty> GetVertexDelta(int vertexIndex)
  60. {
  61. if (_MorphVertices.TryGetValue(vertexIndex, out VertexBuilder<TvG, TvM, VertexEmpty> value))
  62. {
  63. var vertex = _BaseVertexFunc(vertexIndex);
  64. return new VertexBuilder<VertexGeometryDelta, VertexMaterialDelta, VertexEmpty>(
  65. value.Geometry.Subtract(vertex.Geometry),
  66. value.Material.Subtract(vertex.Material));
  67. }
  68. return default;
  69. }
  70. public void SetVertexDelta(int vertexIndex, VertexGeometryDelta geometryDelta, VertexMaterialDelta materialDelta)
  71. {
  72. if (object.Equals(geometryDelta, default(VertexGeometryDelta)))
  73. {
  74. _RemoveVertex(vertexIndex);
  75. return;
  76. }
  77. var vertex = _BaseVertexFunc(vertexIndex);
  78. vertex.Geometry.Add(geometryDelta);
  79. if (typeof(TvM) != typeof(VertexEmpty))
  80. vertex.Material.Add(materialDelta);
  81. _SetVertex(vertexIndex, vertex);
  82. }
  83. IVertexBuilder IPrimitiveMorphTargetReader.GetVertex(int vertexIndex)
  84. {
  85. return _MorphVertices.TryGetValue(vertexIndex, out VertexBuilder<TvG, TvM, VertexEmpty> value) ? value : _BaseVertexFunc(vertexIndex);
  86. }
  87. public VertexBuilder<TvG, TvM, VertexEmpty> GetVertex(int vertexIndex)
  88. {
  89. return _MorphVertices.TryGetValue(vertexIndex, out VertexBuilder<TvG, TvM, VertexEmpty> value) ? value : _BaseVertexFunc(vertexIndex);
  90. }
  91. public void SetVertex(int vertexIndex, VertexBuilder<TvG, TvM, VertexEmpty> vertex)
  92. {
  93. if (object.Equals(vertex, _BaseVertexFunc(vertexIndex)))
  94. {
  95. _RemoveVertex(vertexIndex);
  96. return;
  97. }
  98. _SetVertex(vertexIndex, vertex);
  99. }
  100. private void _SetVertex(int vertexIndex, VertexBuilder<TvG, TvM, VertexEmpty> vertex)
  101. {
  102. _MorphVertices[vertexIndex] = vertex;
  103. }
  104. private void _RemoveVertex(int vertexIndex)
  105. {
  106. _MorphVertices.Remove(vertexIndex);
  107. }
  108. #endregion
  109. #region internals
  110. internal void TransformVertices(Func<VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>> vertexFunc)
  111. {
  112. foreach (var vidx in _MorphVertices.Keys)
  113. {
  114. var g = GetVertex(vidx);
  115. g = vertexFunc(g);
  116. SetVertex(vidx, g);
  117. }
  118. }
  119. internal void SetMorphTargets(IPrimitiveMorphTargetReader other, IReadOnlyDictionary<int, int> vertexMap, Func<IVertexGeometry, VertexBuilder<TvG, TvM, VertexEmpty>> vertexFunc)
  120. {
  121. Guard.NotNull(vertexFunc, nameof(vertexFunc));
  122. var indices = other.GetTargetIndices();
  123. foreach (var srcVidx in indices)
  124. {
  125. var g = vertexFunc(other.GetVertex(srcVidx).GetGeometry());
  126. var dstVidx = srcVidx;
  127. if (vertexMap != null)
  128. {
  129. if (!vertexMap.TryGetValue(srcVidx, out dstVidx)) dstVidx = -1;
  130. }
  131. if (dstVidx >= 0) this.SetVertex(dstVidx, g);
  132. }
  133. }
  134. #endregion
  135. }
  136. /// <summary>
  137. /// Represents the vertex deltas of a specific morph target.
  138. /// <see cref="IMeshBuilder{TMaterial}.UseMorphTarget(int)"/>
  139. /// </summary>
  140. public interface IMorphTargetBuilder
  141. {
  142. IReadOnlyCollection<Vector3> Positions { get; }
  143. IReadOnlyCollection<IVertexGeometry> Vertices { get; }
  144. IReadOnlyList<IVertexGeometry> GetVertices(Vector3 position);
  145. /// <summary>
  146. /// Sets an absolute morph target.
  147. /// </summary>
  148. /// <param name="meshVertex">The base mesh vertex to morph.</param>
  149. /// <param name="morphVertex">The morphed vertex.</param>
  150. void SetVertex(IVertexGeometry meshVertex, IVertexGeometry morphVertex);
  151. /// <summary>
  152. /// Sets an absolute morph target.
  153. /// </summary>
  154. /// <param name="meshVertex">The base mesh vertex to morph.</param>
  155. /// <param name="morphVertex">The morphed vertex.</param>
  156. /// <param name="morphMaterial">The morphed vertex material.</param>
  157. void SetVertex(IVertexGeometry meshVertex, IVertexGeometry morphVertex, IVertexMaterial morphMaterial);
  158. /// <summary>
  159. /// Sets a relative morph target
  160. /// </summary>
  161. /// <param name="meshVertex">The base mesh vertex to morph.</param>
  162. /// <param name="geometryDelta">The offset from <paramref name="meshVertex"/> to morph.</param>
  163. void SetVertexDelta(IVertexGeometry meshVertex, VertexGeometryDelta geometryDelta);
  164. /// <summary>
  165. /// Sets a relative morph target
  166. /// </summary>
  167. /// <param name="meshVertex">The base mesh vertex to morph.</param>
  168. /// <param name="geometryDelta">The offset from <paramref name="meshVertex"/> to morph.</param>
  169. /// <param name="materialDelta">The offset from <paramref name="meshVertex"/> material to morph.</param>
  170. void SetVertexDelta(IVertexGeometry meshVertex, VertexGeometryDelta geometryDelta, VertexMaterialDelta materialDelta);
  171. /// <summary>
  172. /// Sets a relative morph target to all base mesh vertices matching <paramref name="meshPosition"/>.
  173. /// </summary>
  174. /// <param name="meshPosition">The base vertex position.</param>
  175. /// <param name="geometryDelta">The offset to apply to each matching vertex found.</param>
  176. void SetVertexDelta(Vector3 meshPosition, VertexGeometryDelta geometryDelta);
  177. /// <summary>
  178. /// Sets a relative morph target to all base mesh vertices matching <paramref name="meshPosition"/>.
  179. /// </summary>
  180. /// <param name="meshPosition">The base vertex position.</param>
  181. /// <param name="geometryDelta">The offset to apply to each matching vertex found.</param>
  182. /// <param name="materialDelta">The offset to apply to each matching vertex material found.</param>
  183. void SetVertexDelta(Vector3 meshPosition, VertexGeometryDelta geometryDelta, VertexMaterialDelta materialDelta);
  184. }
  185. /// <summary>
  186. /// Represents the vertex deltas of a specific morph target.
  187. /// <see cref="MeshBuilder{TMaterial, TvG, TvM, TvS}.UseMorphTarget(int)"/>
  188. /// </summary>
  189. /// <typeparam name="TMaterial">The material type used by the base mesh.</typeparam>
  190. /// <typeparam name="TvG">The vertex geometry type used by the base mesh.</typeparam>
  191. /// <typeparam name="TvS">The vertex skinning type used by the base mesh.</typeparam>
  192. /// <typeparam name="TvM">The vertex material type used by the base mesh.</typeparam>
  193. /// <remarks>
  194. /// Morph targets are stored separately on each <see cref="PrimitiveBuilder{TMaterial, TvG, TvM, TvS}"/>,
  195. /// so connecting vertices between two primitives might be duplicated. This means that when we set
  196. /// a displaced vertex, we must be sure we do so for all instances we can find.
  197. /// </remarks>
  198. public sealed class MorphTargetBuilder<TMaterial, TvG, TvS, TvM> : IMorphTargetBuilder
  199. where TvG : struct, IVertexGeometry
  200. where TvM : struct, IVertexMaterial
  201. where TvS : struct, IVertexSkinning
  202. {
  203. #region lifecycle
  204. internal MorphTargetBuilder(MeshBuilder<TMaterial, TvG, TvM, TvS> mesh, int morphTargetIndex)
  205. {
  206. _Mesh = mesh;
  207. _MorphTargetIndex = morphTargetIndex;
  208. foreach (var prim in _Mesh.Primitives)
  209. {
  210. for (int vidx = 0; vidx < prim.Vertices.Count; ++vidx)
  211. {
  212. var key = prim.Vertices[vidx].Geometry;
  213. if (!_Vertices.TryGetValue(key, out List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)> val))
  214. {
  215. _Vertices[key] = val = new List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)>();
  216. }
  217. val.Add((prim, vidx));
  218. if (!_Positions.TryGetValue(key.GetPosition(), out List<TvG> geos))
  219. {
  220. _Positions[key.GetPosition()] = geos = new List<TvG>();
  221. }
  222. geos.Add(key);
  223. }
  224. }
  225. }
  226. #endregion
  227. #region data
  228. private readonly MeshBuilder<TMaterial, TvG, TvM, TvS> _Mesh;
  229. private readonly int _MorphTargetIndex;
  230. private readonly Dictionary<TvG, List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)>> _Vertices = new Dictionary<TvG, List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)>>();
  231. private readonly Dictionary<Vector3, List<TvG>> _Positions = new Dictionary<Vector3, List<TvG>>();
  232. #endregion
  233. #region properties
  234. public IReadOnlyCollection<Vector3> Positions => _Positions.Keys;
  235. public IReadOnlyCollection<TvG> Vertices => _Vertices.Keys;
  236. #endregion
  237. #region API
  238. public IReadOnlyList<TvG> GetVertices(Vector3 position)
  239. {
  240. return _Positions.TryGetValue(position, out List<TvG> geos) ? (IReadOnlyList<TvG>)geos : Array.Empty<TvG>();
  241. }
  242. public void SetVertexDelta(Vector3 key, VertexGeometryDelta geometryDelta)
  243. {
  244. if (_Positions.TryGetValue(key, out List<TvG> geos))
  245. {
  246. foreach (var g in geos) SetVertexDelta(g, geometryDelta, VertexMaterialDelta.Zero);
  247. }
  248. }
  249. public void SetVertexDelta(Vector3 key, VertexGeometryDelta geometryDelta, VertexMaterialDelta materialDelta)
  250. {
  251. if (_Positions.TryGetValue(key, out List<TvG> geos))
  252. {
  253. foreach (var g in geos) SetVertexDelta(g, geometryDelta, materialDelta);
  254. }
  255. }
  256. public void SetVertexDelta(TvG meshVertex, VertexGeometryDelta geometryDelta)
  257. {
  258. if (_Vertices.TryGetValue(meshVertex, out List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)> val))
  259. {
  260. foreach (var entry in val)
  261. {
  262. entry.Item1
  263. ._UseMorphTarget(_MorphTargetIndex)
  264. .SetVertexDelta(entry.Item2, geometryDelta, VertexMaterialDelta.Zero);
  265. }
  266. }
  267. }
  268. public void SetVertexDelta(TvG meshVertex, VertexGeometryDelta geometryDelta, VertexMaterialDelta materialDelta)
  269. {
  270. if (_Vertices.TryGetValue(meshVertex, out List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)> val))
  271. {
  272. foreach (var entry in val)
  273. {
  274. entry.Item1
  275. ._UseMorphTarget(_MorphTargetIndex)
  276. .SetVertexDelta(entry.Item2, geometryDelta, materialDelta);
  277. }
  278. }
  279. }
  280. public void SetVertex(TvG meshVertex, VertexBuilder<TvG, TvM, VertexEmpty> morphVertex)
  281. {
  282. if (_Vertices.TryGetValue(meshVertex, out List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)> val))
  283. {
  284. foreach (var entry in val)
  285. {
  286. entry.Item1
  287. ._UseMorphTarget(_MorphTargetIndex)
  288. .SetVertex(entry.Item2, morphVertex);
  289. }
  290. }
  291. }
  292. public void SetVertex(TvG meshVertex, TvG morphVertex)
  293. {
  294. if (_Vertices.TryGetValue(meshVertex, out List<(PrimitiveBuilder<TMaterial, TvG, TvM, TvS>, int)> val))
  295. {
  296. foreach (var entry in val)
  297. {
  298. var vertexMaterial = entry.Item1.Vertices[entry.Item2].Material;
  299. entry.Item1
  300. ._UseMorphTarget(_MorphTargetIndex)
  301. .SetVertex(entry.Item2, new VertexBuilder<TvG, TvM, VertexEmpty>(morphVertex, vertexMaterial));
  302. }
  303. }
  304. }
  305. #endregion
  306. #region IMorphTargetBuilder
  307. IReadOnlyCollection<IVertexGeometry> IMorphTargetBuilder.Vertices => (IReadOnlyList<IVertexGeometry>)(IReadOnlyCollection<TvG>)_Vertices.Keys;
  308. IReadOnlyList<IVertexGeometry> IMorphTargetBuilder.GetVertices(Vector3 position)
  309. {
  310. return _Positions.TryGetValue(position, out List<TvG> geos)
  311. ? (IReadOnlyList<IVertexGeometry>)geos
  312. : Array.Empty<IVertexGeometry>();
  313. }
  314. void IMorphTargetBuilder.SetVertex(IVertexGeometry meshVertex, IVertexGeometry morphVertex)
  315. {
  316. SetVertex(meshVertex.ConvertToGeometry<TvG>(),
  317. new VertexBuilder<TvG, TvM, VertexEmpty>(morphVertex.ConvertToGeometry<TvG>(), default(VertexEmpty).ConvertToMaterial<TvM>()));
  318. }
  319. void IMorphTargetBuilder.SetVertex(IVertexGeometry meshVertex, IVertexGeometry morphVertex, IVertexMaterial morphMaterial)
  320. {
  321. SetVertex(meshVertex.ConvertToGeometry<TvG>(),
  322. new VertexBuilder<TvG, TvM, VertexEmpty>(morphVertex.ConvertToGeometry<TvG>(), morphMaterial.ConvertToMaterial<TvM>()));
  323. }
  324. void IMorphTargetBuilder.SetVertexDelta(IVertexGeometry meshVertex, VertexGeometryDelta geometryDelta)
  325. {
  326. SetVertexDelta(meshVertex.ConvertToGeometry<TvG>(), geometryDelta, VertexMaterialDelta.Zero);
  327. }
  328. void IMorphTargetBuilder.SetVertexDelta(IVertexGeometry meshVertex, VertexGeometryDelta geometryDelta, VertexMaterialDelta materialDelta)
  329. {
  330. SetVertexDelta(meshVertex.ConvertToGeometry<TvG>(), geometryDelta, materialDelta);
  331. }
  332. #endregion
  333. }
  334. }