説明なし
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

WeightEditor.cs 7.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace UnityEditor.U2D.Animation
  5. {
  6. internal enum WeightEditorMode
  7. {
  8. AddAndSubtract,
  9. GrowAndShrink,
  10. Smooth
  11. }
  12. internal class WeightEditor
  13. {
  14. public BaseSpriteMeshData spriteMeshData
  15. {
  16. get => m_SpriteMeshDataController.spriteMeshData;
  17. set => m_SpriteMeshDataController.spriteMeshData = value;
  18. }
  19. public ICacheUndo cacheUndo { get; set; }
  20. public WeightEditorMode mode { get; set; }
  21. public int boneIndex { get; set; }
  22. public ISelection<int> selection { get; set; }
  23. public bool emptySelectionEditsAll { get; set; }
  24. public bool autoNormalize { get; set; }
  25. WeightEditorMode currentMode { get; set; }
  26. bool useRelativeValues { get; set; }
  27. SpriteMeshDataController m_SpriteMeshDataController = new SpriteMeshDataController();
  28. const int k_MaxSmoothIterations = 8;
  29. float[] m_SmoothValues;
  30. readonly List<BoneWeight[]> m_SmoothedBoneWeights = new List<BoneWeight[]>();
  31. readonly List<BoneWeight> m_StoredBoneWeights = new List<BoneWeight>();
  32. int boneCount => spriteMeshData != null ? spriteMeshData.boneCount : 0;
  33. public WeightEditor()
  34. {
  35. autoNormalize = true;
  36. }
  37. public void OnEditStart(bool relative)
  38. {
  39. Validate();
  40. RegisterUndo();
  41. currentMode = mode;
  42. useRelativeValues = relative;
  43. if (!useRelativeValues)
  44. StoreBoneWeights();
  45. if (mode == WeightEditorMode.Smooth)
  46. PrepareSmoothingBuffers();
  47. }
  48. public void OnEditEnd()
  49. {
  50. Validate();
  51. if (currentMode == WeightEditorMode.AddAndSubtract)
  52. {
  53. for (int i = 0; i < spriteMeshData.vertexCount; ++i)
  54. spriteMeshData.vertexWeights[i].Clamp(4);
  55. }
  56. if (autoNormalize)
  57. m_SpriteMeshDataController.NormalizeWeights(null);
  58. m_SpriteMeshDataController.SortTrianglesByDepth();
  59. }
  60. public void DoEdit(float value)
  61. {
  62. Validate();
  63. if (!useRelativeValues)
  64. RestoreBoneWeights();
  65. if (currentMode == WeightEditorMode.AddAndSubtract)
  66. SetWeight(value);
  67. else if (currentMode == WeightEditorMode.GrowAndShrink)
  68. SetWeight(value, false);
  69. else if (currentMode == WeightEditorMode.Smooth)
  70. SmoothWeights(value);
  71. }
  72. void Validate()
  73. {
  74. if (spriteMeshData == null)
  75. throw (new Exception(TextContent.noSpriteSelected));
  76. }
  77. void RegisterUndo()
  78. {
  79. Debug.Assert(cacheUndo != null);
  80. cacheUndo.BeginUndoOperation(TextContent.editWeights);
  81. }
  82. void SetWeight(float value, bool createNewChannel = true)
  83. {
  84. if (boneIndex == -1 || spriteMeshData == null)
  85. return;
  86. Debug.Assert(selection != null);
  87. for (var i = 0; i < spriteMeshData.vertexCount; ++i)
  88. {
  89. if (selection.Count == 0 && emptySelectionEditsAll ||
  90. selection.Count > 0 && selection.Contains(i))
  91. {
  92. var editableBoneWeight = spriteMeshData.vertexWeights[i];
  93. var channel = editableBoneWeight.GetChannelFromBoneIndex(boneIndex);
  94. if (channel == -1)
  95. {
  96. if (createNewChannel && value > 0f)
  97. {
  98. editableBoneWeight.AddChannel(boneIndex, 0f, true);
  99. channel = editableBoneWeight.GetChannelFromBoneIndex(boneIndex);
  100. }
  101. else
  102. {
  103. continue;
  104. }
  105. }
  106. editableBoneWeight[channel].weight += value;
  107. if (editableBoneWeight.Sum() > 1f)
  108. editableBoneWeight.CompensateOtherChannels(channel);
  109. editableBoneWeight.FilterChannels(0f);
  110. }
  111. }
  112. }
  113. void SmoothWeights(float value)
  114. {
  115. Debug.Assert(selection != null);
  116. for (var i = 0; i < spriteMeshData.vertexCount; ++i)
  117. {
  118. if (selection.Count == 0 && emptySelectionEditsAll ||
  119. selection.Count > 0 && selection.Contains(i))
  120. {
  121. var smoothValue = m_SmoothValues[i];
  122. if (smoothValue >= k_MaxSmoothIterations)
  123. continue;
  124. m_SmoothValues[i] = Mathf.Clamp(smoothValue + value, 0f, k_MaxSmoothIterations);
  125. var lerpValue = GetLerpValue(m_SmoothValues[i]);
  126. var lerpIndex = GetLerpIndex(m_SmoothValues[i]);
  127. var smoothedBoneWeightsFloor = GetSmoothedBoneWeights(lerpIndex - 1);
  128. var smoothedBoneWeightsCeil = GetSmoothedBoneWeights(lerpIndex);
  129. var boneWeight = EditableBoneWeightUtility.Lerp(smoothedBoneWeightsFloor[i], smoothedBoneWeightsCeil[i], lerpValue);
  130. spriteMeshData.vertexWeights[i].SetFromBoneWeight(boneWeight);
  131. }
  132. }
  133. }
  134. void PrepareSmoothingBuffers()
  135. {
  136. if (m_SmoothValues == null || m_SmoothValues.Length != spriteMeshData.vertexCount)
  137. m_SmoothValues = new float[spriteMeshData.vertexCount];
  138. Array.Clear(m_SmoothValues, 0, m_SmoothValues.Length);
  139. m_SmoothedBoneWeights.Clear();
  140. var boneWeights = new BoneWeight[spriteMeshData.vertexCount];
  141. for (var i = 0; i < spriteMeshData.vertexCount; i++)
  142. {
  143. var editableBoneWeight = spriteMeshData.vertexWeights[i];
  144. boneWeights[i] = editableBoneWeight.ToBoneWeight(false);
  145. }
  146. m_SmoothedBoneWeights.Add(boneWeights);
  147. }
  148. BoneWeight[] GetSmoothedBoneWeights(int lerpIndex)
  149. {
  150. Debug.Assert(lerpIndex >= 0);
  151. while (lerpIndex >= m_SmoothedBoneWeights.Count && lerpIndex <= k_MaxSmoothIterations)
  152. {
  153. SmoothingUtility.SmoothWeights(m_SmoothedBoneWeights[^1], spriteMeshData.indices, boneCount, out var boneWeights);
  154. m_SmoothedBoneWeights.Add(boneWeights);
  155. }
  156. return m_SmoothedBoneWeights[Mathf.Min(lerpIndex, k_MaxSmoothIterations)];
  157. }
  158. static float GetLerpValue(float smoothValue)
  159. {
  160. Debug.Assert(smoothValue >= 0f);
  161. return smoothValue - Mathf.Floor(smoothValue);
  162. }
  163. static int GetLerpIndex(float smoothValue)
  164. {
  165. Debug.Assert(smoothValue >= 0f);
  166. return Mathf.RoundToInt(Mathf.Floor(smoothValue) + 1);
  167. }
  168. void StoreBoneWeights()
  169. {
  170. Debug.Assert(selection != null);
  171. m_StoredBoneWeights.Clear();
  172. for (var i = 0; i < spriteMeshData.vertexCount; i++)
  173. {
  174. var editableBoneWeight = spriteMeshData.vertexWeights[i];
  175. m_StoredBoneWeights.Add(editableBoneWeight.ToBoneWeight(false));
  176. }
  177. }
  178. void RestoreBoneWeights()
  179. {
  180. Debug.Assert(selection != null);
  181. for (var i = 0; i < spriteMeshData.vertexCount; i++)
  182. {
  183. var editableBoneWeight = spriteMeshData.vertexWeights[i];
  184. editableBoneWeight.SetFromBoneWeight(m_StoredBoneWeights[i]);
  185. }
  186. if (m_SmoothValues != null)
  187. Array.Clear(m_SmoothValues, 0, m_SmoothValues.Length);
  188. }
  189. }
  190. }