暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

WeightPainterTool.cs 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. using UnityEngine;
  2. using UnityEditor.U2D.Common;
  3. using UnityEditor.U2D.Layout;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. namespace UnityEditor.U2D.Animation
  8. {
  9. internal enum WeightPainterMode
  10. {
  11. Brush,
  12. Slider
  13. }
  14. internal class WeightPainterTool : MeshToolWrapper
  15. {
  16. private WeightPainterPanel m_WeightPainterPanel;
  17. private WeightEditor m_WeightEditor = new WeightEditor();
  18. private Brush m_Brush = new Brush(new GUIWrapper());
  19. private ISelection<int> m_BrushSelection = new IndexedSelection();
  20. private CircleVertexSelector m_CircleVertexSelector = new CircleVertexSelector();
  21. public WeightPainterMode paintMode
  22. {
  23. get { return m_WeightPainterPanel.paintMode; }
  24. set { m_WeightPainterPanel.paintMode = value; }
  25. }
  26. public override int defaultControlID
  27. {
  28. get { return m_Brush.controlID; }
  29. }
  30. internal override void OnCreate()
  31. {
  32. m_WeightEditor.cacheUndo = skinningCache;
  33. m_Brush.onMove += (brush) =>
  34. {
  35. UpdateBrushSelection(brush);
  36. };
  37. m_Brush.onRepaint += (brush) =>
  38. {
  39. DrawBrush(brush);
  40. };
  41. m_Brush.onSize += (brush) =>
  42. {
  43. UpdateBrushSelection(brush);
  44. m_WeightPainterPanel.size = Mathf.RoundToInt(brush.size);
  45. };
  46. m_Brush.onStrokeBegin += (brush) =>
  47. {
  48. UpdateBrushSelection(brush);
  49. EditStart(m_BrushSelection, true);
  50. };
  51. m_Brush.onStrokeDelta += (brush) =>
  52. {
  53. if (m_BrushSelection.Count > 0)
  54. meshTool.UpdateWeights();
  55. };
  56. m_Brush.onStrokeStep += (brush) =>
  57. {
  58. UpdateBrushSelection(brush);
  59. var hardness = brush.hardness / 100f;
  60. if (EditorGUI.actionKey)
  61. hardness *= -1f;
  62. EditWeights(hardness, false);
  63. };
  64. m_Brush.onStrokeEnd += (brush) =>
  65. {
  66. EditEnd();
  67. };
  68. }
  69. public string panelTitle
  70. {
  71. set { m_WeightPainterPanel.title = value; }
  72. }
  73. protected override void OnActivate()
  74. {
  75. base.OnActivate();
  76. m_WeightPainterPanel.SetHiddenFromLayout(false);
  77. skinningCache.events.selectedSpriteChanged.AddListener(OnSelectedSpriteChanged);
  78. skinningCache.events.skinningModeChanged.AddListener(OnSkinningModeChanged);
  79. skinningCache.events.boneSelectionChanged.AddListener(OnBoneSelectionChanged);
  80. m_Brush.size = skinningCache.brushSize;
  81. m_Brush.hardness = skinningCache.brushHardness;
  82. m_Brush.step = skinningCache.brushStep;
  83. m_WeightPainterPanel.size = (int) m_Brush.size;
  84. m_WeightPainterPanel.hardness = (int) m_Brush.hardness;
  85. m_WeightPainterPanel.step = (int) m_Brush.step;
  86. UpdatePanel();
  87. }
  88. protected override void OnDeactivate()
  89. {
  90. base.OnDeactivate();
  91. skinningCache.events.selectedSpriteChanged.RemoveListener(OnSelectedSpriteChanged);
  92. skinningCache.events.skinningModeChanged.RemoveListener(OnSkinningModeChanged);
  93. skinningCache.events.boneSelectionChanged.RemoveListener(OnBoneSelectionChanged);
  94. m_WeightPainterPanel.SetHiddenFromLayout(true);
  95. }
  96. private void OnBoneSelectionChanged()
  97. {
  98. UpdateSelectedBone();
  99. }
  100. private void OnSelectedSpriteChanged(SpriteCache sprite)
  101. {
  102. UpdatePanel();
  103. }
  104. private void OnSkinningModeChanged(SkinningMode mode)
  105. {
  106. UpdatePanel();
  107. }
  108. private string[] GetSkeletonBonesNames()
  109. {
  110. var names = new List<string>() { WeightPainterPanel.kNone };
  111. var skeleton = skinningCache.GetEffectiveSkeleton(skinningCache.selectedSprite);
  112. if (skeleton != null)
  113. names.AddRange(GetUniqueBoneNames(skeleton.bones, skeleton));
  114. return names.ToArray();
  115. }
  116. private string[] GetMeshBoneNames()
  117. {
  118. var mesh = meshTool.mesh;
  119. var skeleton = skinningCache.GetEffectiveSkeleton(skinningCache.selectedSprite);
  120. if (mesh != null && skeleton != null)
  121. {
  122. var bones = meshTool.mesh.bones.ToSpriteSheetIfNeeded();
  123. return GetUniqueBoneNames(bones, skeleton);
  124. }
  125. return new string[0];
  126. }
  127. private string[] GetUniqueBoneNames(BoneCache[] bones, SkeletonCache skeleton)
  128. {
  129. return Array.ConvertAll(bones, b => skeleton.GetUniqueName(b));
  130. }
  131. private void UpdatePanel()
  132. {
  133. m_WeightPainterPanel.SetActive(skinningCache.selectedSprite != null);
  134. m_WeightPainterPanel.UpdateWeightInspector(meshTool.mesh, GetMeshBoneNames(), skinningCache.vertexSelection, skinningCache);
  135. m_WeightPainterPanel.UpdatePanel(GetSkeletonBonesNames());
  136. UpdateSelectedBone();
  137. }
  138. private void UpdateSelectedBone()
  139. {
  140. var boneName = WeightPainterPanel.kNone;
  141. var bone = skinningCache.skeletonSelection.activeElement.ToSpriteSheetIfNeeded();
  142. var skeleton = skinningCache.GetEffectiveSkeleton(skinningCache.selectedSprite);
  143. if (skeleton != null && skeleton.Contains(bone))
  144. boneName = skeleton.GetUniqueName(bone);
  145. m_WeightPainterPanel.SetBoneSelectionByName(boneName);
  146. }
  147. public override void Initialize(LayoutOverlay layout)
  148. {
  149. base.Initialize(layout);
  150. m_WeightPainterPanel = WeightPainterPanel.GenerateFromUXML();
  151. m_WeightPainterPanel.SetHiddenFromLayout(true);
  152. layout.rightOverlay.Add(m_WeightPainterPanel);
  153. m_WeightPainterPanel.sliderStarted += () =>
  154. {
  155. EditStart(skinningCache.vertexSelection, false);
  156. };
  157. m_WeightPainterPanel.sliderChanged += (value) =>
  158. {
  159. EditWeights(value, true);
  160. meshTool.UpdateWeights();
  161. };
  162. m_WeightPainterPanel.sliderEnded += () =>
  163. {
  164. EditEnd();
  165. };
  166. m_WeightPainterPanel.bonePopupChanged += (i) =>
  167. {
  168. var skeleton = skinningCache.GetEffectiveSkeleton(skinningCache.selectedSprite);
  169. if (skeleton != null)
  170. {
  171. BoneCache bone = null;
  172. if (i != -1)
  173. bone = skeleton.GetBone(i).ToCharacterIfNeeded();
  174. if(bone != skinningCache.skeletonSelection.activeElement)
  175. {
  176. using (skinningCache.UndoScope(TextContent.boneSelection))
  177. {
  178. skinningCache.skeletonSelection.activeElement = bone;
  179. InvokeBoneSelectionChanged();
  180. }
  181. }
  182. }
  183. };
  184. m_WeightPainterPanel.weightsChanged += () => meshTool.UpdateWeights();
  185. }
  186. internal void SetWeightPainterPanelTitle(string title)
  187. {
  188. m_WeightPainterPanel.title = title;
  189. }
  190. private void AssociateSelectedBoneToCharacterPart()
  191. {
  192. var mesh = meshTool.mesh;
  193. if (skinningCache.hasCharacter
  194. && skinningCache.mode == SkinningMode.Character
  195. && m_WeightPainterPanel.boneIndex != -1
  196. && mesh != null)
  197. {
  198. var skeleton = skinningCache.character.skeleton;
  199. Debug.Assert(skeleton != null);
  200. var bone = skeleton.GetBone(m_WeightPainterPanel.boneIndex);
  201. if (!mesh.ContainsBone(bone))
  202. {
  203. using (skinningCache.UndoScope(TextContent.addBoneInfluence))
  204. {
  205. var characterPart = mesh.sprite.GetCharacterPart();
  206. var characterBones = characterPart.bones.ToList();
  207. characterBones.Add(bone);
  208. characterPart.bones = characterBones.ToArray();
  209. skinningCache.events.characterPartChanged.Invoke(characterPart);
  210. m_WeightPainterPanel.UpdateWeightInspector(meshTool.mesh, GetMeshBoneNames(), skinningCache.vertexSelection, skinningCache);
  211. }
  212. }
  213. }
  214. }
  215. private void EditStart(ISelection<int> selection, bool relative)
  216. {
  217. AssociateSelectedBoneToCharacterPart();
  218. SetupWeightEditor(selection);
  219. if (m_WeightEditor.spriteMeshData != null)
  220. m_WeightEditor.OnEditStart(relative);
  221. }
  222. private void EditWeights(float hardness, bool emptySelectionEditsAll)
  223. {
  224. m_WeightEditor.emptySelectionEditsAll = emptySelectionEditsAll;
  225. if (m_WeightEditor.spriteMeshData != null)
  226. m_WeightEditor.DoEdit(hardness);
  227. }
  228. private void EditEnd()
  229. {
  230. if (m_WeightEditor.spriteMeshData != null)
  231. {
  232. m_WeightEditor.OnEditEnd();
  233. meshTool.UpdateWeights();
  234. }
  235. }
  236. private void InvokeBoneSelectionChanged()
  237. {
  238. skinningCache.events.boneSelectionChanged.RemoveListener(OnBoneSelectionChanged);
  239. skinningCache.events.boneSelectionChanged.Invoke();
  240. skinningCache.events.boneSelectionChanged.AddListener(OnBoneSelectionChanged);
  241. }
  242. private int ConvertBoneIndex(int index)
  243. {
  244. if (index != -1 && meshTool.mesh != null)
  245. {
  246. var skeleton = skinningCache.GetEffectiveSkeleton(meshTool.mesh.sprite);
  247. if (skeleton != null)
  248. {
  249. var bone = skeleton.GetBone(index).ToCharacterIfNeeded();
  250. index = Array.IndexOf(meshTool.mesh.bones, bone);
  251. }
  252. }
  253. return index;
  254. }
  255. private void SetupWeightEditor(ISelection<int> selection)
  256. {
  257. m_WeightEditor.spriteMeshData = meshTool.mesh;
  258. m_WeightEditor.mode = m_WeightPainterPanel.mode;
  259. m_WeightEditor.boneIndex = ConvertBoneIndex(m_WeightPainterPanel.boneIndex);
  260. m_WeightEditor.autoNormalize = m_WeightPainterPanel.normalize;
  261. m_WeightEditor.selection = selection;
  262. m_WeightEditor.emptySelectionEditsAll = true;
  263. }
  264. private void UpdateBrushSelection(Brush brush)
  265. {
  266. m_BrushSelection.Clear();
  267. m_CircleVertexSelector.spriteMeshData = meshTool.mesh;
  268. m_CircleVertexSelector.position = brush.position;
  269. m_CircleVertexSelector.radius = brush.size;
  270. m_CircleVertexSelector.selection = m_BrushSelection;
  271. m_CircleVertexSelector.Select();
  272. }
  273. private void DrawBrush(Brush brush)
  274. {
  275. var oldColor = Handles.color;
  276. Handles.color = Color.white;
  277. if (EditorGUI.actionKey)
  278. Handles.color = Color.red;
  279. if (brush.isHot)
  280. Handles.color = Color.yellow;
  281. Handles.DrawWireDisc(brush.position, Vector3.forward, brush.size);
  282. Handles.color = oldColor;
  283. }
  284. protected override void OnGUI()
  285. {
  286. m_MeshPreviewBehaviour.showWeightMap = true;
  287. m_MeshPreviewBehaviour.overlaySelected = true;
  288. skeletonTool.skeletonStyle = SkeletonStyles.WeightMap;
  289. skeletonMode = SkeletonMode.EditPose;
  290. meshMode = SpriteMeshViewMode.EditGeometry;
  291. disableMeshEditor = true;
  292. var isBoneHovered = skeletonTool.hoveredBone != null && !m_Brush.isHot;
  293. var useBrush = paintMode == WeightPainterMode.Brush;
  294. meshTool.selectionOverride = null;
  295. if (useBrush)
  296. meshTool.selectionOverride = m_BrushSelection;
  297. DoSkeletonGUI();
  298. DoMeshGUI();
  299. if (useBrush && !isBoneHovered)
  300. {
  301. var handlesMatrix = Handles.matrix;
  302. var selectedSprite = skinningCache.selectedSprite;
  303. var matrix = Matrix4x4.identity;
  304. if (selectedSprite != null)
  305. matrix = selectedSprite.GetLocalToWorldMatrixFromMode();
  306. Handles.matrix *= matrix;
  307. skinningCache.brushSize = m_Brush.size = m_WeightPainterPanel.size;
  308. skinningCache.brushHardness = m_Brush.hardness = m_WeightPainterPanel.hardness;
  309. skinningCache.brushStep = m_Brush.step = m_WeightPainterPanel.step;
  310. if (m_Brush.isHot || !skinningCache.IsOnVisualElement())
  311. {
  312. meshTool.BeginPositionOverride();
  313. m_Brush.OnGUI();
  314. meshTool.EndPositionOverride();
  315. }
  316. Handles.matrix = handlesMatrix;
  317. }
  318. }
  319. }
  320. }