WeightEditor.cs 8.1 KB

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