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

GenerateGeometryTool.cs 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. using System;
  2. using System.Collections.Generic;
  3. using Unity.Collections;
  4. using Unity.Jobs;
  5. using Unity.Mathematics;
  6. using UnityEditor.U2D.Common;
  7. using UnityEditor.U2D.Layout;
  8. using UnityEngine;
  9. namespace UnityEditor.U2D.Animation
  10. {
  11. internal class GenerateGeometryTool : MeshToolWrapper
  12. {
  13. private const float kWeightTolerance = 0.1f;
  14. private SpriteMeshDataController m_SpriteMeshDataController = new SpriteMeshDataController();
  15. private ITriangulator m_Triangulator;
  16. private IOutlineGenerator m_OutlineGenerator;
  17. private IWeightsGenerator m_WeightGenerator;
  18. private GenerateGeometryPanel m_GenerateGeometryPanel;
  19. internal override void OnCreate()
  20. {
  21. m_Triangulator = new Triangulator();
  22. m_OutlineGenerator = new OutlineGenerator();
  23. m_WeightGenerator = new BoundedBiharmonicWeightsGenerator();
  24. }
  25. public override void Initialize(LayoutOverlay layout)
  26. {
  27. base.Initialize(layout);
  28. m_GenerateGeometryPanel = GenerateGeometryPanel.GenerateFromUXML();
  29. m_GenerateGeometryPanel.skinningCache = skinningCache;
  30. layout.rightOverlay.Add(m_GenerateGeometryPanel);
  31. BindElements();
  32. Hide();
  33. }
  34. private void BindElements()
  35. {
  36. Debug.Assert(m_GenerateGeometryPanel != null);
  37. m_GenerateGeometryPanel.onAutoGenerateGeometry += (float detail, byte alpha, float subdivide) =>
  38. {
  39. var selectedSprite = skinningCache.selectedSprite;
  40. if (selectedSprite != null)
  41. GenerateGeometryForSprites(new[] { selectedSprite }, detail, alpha, subdivide);
  42. };
  43. m_GenerateGeometryPanel.onAutoGenerateGeometryAll += (float detail, byte alpha, float subdivide) =>
  44. {
  45. var sprites = skinningCache.GetSprites();
  46. GenerateGeometryForSprites(sprites, detail, alpha, subdivide);
  47. };
  48. }
  49. void GenerateGeometryForSprites(SpriteCache[] sprites, float detail, byte alpha, float subdivide)
  50. {
  51. var cancelProgress = false;
  52. using (skinningCache.UndoScope(TextContent.generateGeometry))
  53. {
  54. float progressMax = sprites.Length * 4; // for ProgressBar
  55. int validSpriteCount = 0;
  56. //
  57. // Generate Outline
  58. //
  59. for (var i = 0; i < sprites.Length; ++i)
  60. {
  61. var sprite = sprites[i];
  62. if (!sprite.IsVisible())
  63. continue;
  64. Debug.Assert(sprite != null);
  65. var mesh = sprite.GetMesh();
  66. Debug.Assert(mesh != null);
  67. m_SpriteMeshDataController.spriteMeshData = mesh;
  68. validSpriteCount++;
  69. cancelProgress = EditorUtility.DisplayCancelableProgressBar(TextContent.generatingOutline, sprite.name, i / progressMax);
  70. if (cancelProgress)
  71. break;
  72. m_SpriteMeshDataController.OutlineFromAlpha(m_OutlineGenerator, mesh.textureDataProvider, detail / 100f, alpha);
  73. }
  74. //
  75. // Generate Base Mesh Threaded.
  76. //
  77. const int maxDataCount = 65536;
  78. var spriteList = new List<SpriteJobData>();
  79. var jobHandles = new NativeArray<JobHandle>(validSpriteCount, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
  80. int jobCount = 0;
  81. for (var i = 0; i < sprites.Length; ++i)
  82. {
  83. var sprite = sprites[i];
  84. if (!sprite.IsVisible())
  85. continue;
  86. cancelProgress = EditorUtility.DisplayCancelableProgressBar(TextContent.triangulatingGeometry, sprite.name, 0.25f + (i / progressMax));
  87. if (cancelProgress)
  88. break;
  89. var mesh = sprite.GetMesh();
  90. m_SpriteMeshDataController.spriteMeshData = mesh;
  91. SpriteJobData sd = new SpriteJobData();
  92. sd.spriteMesh = mesh;
  93. sd.vertices = new NativeArray<float2>(maxDataCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
  94. sd.edges = new NativeArray<int2>(maxDataCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
  95. sd.indices = new NativeArray<int>(maxDataCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
  96. sd.weights = new NativeArray<BoneWeight>(maxDataCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
  97. sd.result = new NativeArray<int4>(1, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
  98. sd.result[0] = int4.zero;
  99. spriteList.Add(sd);
  100. if (m_GenerateGeometryPanel.generateWeights)
  101. {
  102. jobHandles[jobCount] = m_SpriteMeshDataController.TriangulateJob(m_Triangulator, sd);
  103. }
  104. else
  105. {
  106. jobHandles[jobCount] = default(JobHandle);
  107. m_SpriteMeshDataController.Triangulate(m_Triangulator);
  108. }
  109. jobCount++;
  110. }
  111. JobHandle.CombineDependencies(jobHandles).Complete();
  112. //
  113. // Generate Base Mesh Fallback.
  114. //
  115. for (var i = 0; i < spriteList.Count; i++)
  116. {
  117. var sd = spriteList[i];
  118. if (math.all(sd.result[0].xy))
  119. {
  120. sd.spriteMesh.Clear();
  121. var edges = new int2[sd.result[0].z];
  122. var indices = new int[sd.result[0].y];
  123. for (var j = 0; j < sd.result[0].x; ++j)
  124. sd.spriteMesh.AddVertex(sd.vertices[j], default(BoneWeight));
  125. for (var j = 0; j < sd.result[0].y; ++j)
  126. indices[j] = sd.indices[j];
  127. for (var j = 0; j < sd.result[0].z; ++j)
  128. edges[j] = sd.edges[j];
  129. sd.spriteMesh.SetEdges(edges);
  130. sd.spriteMesh.SetIndices(indices);
  131. }
  132. else
  133. {
  134. m_SpriteMeshDataController.spriteMeshData = sd.spriteMesh;
  135. m_SpriteMeshDataController.Triangulate(m_Triangulator);
  136. }
  137. }
  138. //
  139. // Subdivide.
  140. //
  141. jobCount = 0;
  142. if (subdivide > 0f)
  143. {
  144. var largestAreaFactor = subdivide != 0 ? Mathf.Lerp(0.5f, 0.05f, Math.Min(subdivide, 100f) / 100f) : subdivide;
  145. for (var i = 0; i < sprites.Length; ++i)
  146. {
  147. var sprite = sprites[i];
  148. if (!sprite.IsVisible())
  149. continue;
  150. cancelProgress = EditorUtility.DisplayCancelableProgressBar(TextContent.subdividingGeometry, sprite.name, 0.5f + (i / progressMax));
  151. if (cancelProgress)
  152. break;
  153. var mesh = sprite.GetMesh();
  154. m_SpriteMeshDataController.spriteMeshData = mesh;
  155. var sd = spriteList[i];
  156. sd.spriteMesh = mesh;
  157. sd.result[0] = int4.zero;
  158. m_SpriteMeshDataController.Subdivide(m_Triangulator, sd, largestAreaFactor, 0f);
  159. }
  160. }
  161. //
  162. // Weight.
  163. //
  164. jobCount = 0;
  165. if (m_GenerateGeometryPanel.generateWeights)
  166. {
  167. for (var i = 0; i < sprites.Length; i++)
  168. {
  169. var sprite = sprites[i];
  170. if (!sprite.IsVisible())
  171. continue;
  172. var mesh = sprite.GetMesh();
  173. m_SpriteMeshDataController.spriteMeshData = mesh;
  174. cancelProgress = EditorUtility.DisplayCancelableProgressBar(TextContent.generatingWeights, sprite.name, 0.75f + (i / progressMax));
  175. if (cancelProgress)
  176. break;
  177. var sd = spriteList[i];
  178. jobHandles[jobCount] = GenerateWeights(sprite, sd);
  179. jobCount++;
  180. }
  181. // Weight
  182. JobHandle.CombineDependencies(jobHandles).Complete();
  183. for (var i = 0; i < sprites.Length; i++)
  184. {
  185. var sprite = sprites[i];
  186. if (!sprite.IsVisible())
  187. continue;
  188. var mesh = sprite.GetMesh();
  189. m_SpriteMeshDataController.spriteMeshData = mesh;
  190. var sd = spriteList[i];
  191. for (var j = 0; j < mesh.vertexCount; ++j)
  192. {
  193. var editableBoneWeight = EditableBoneWeightUtility.CreateFromBoneWeight(sd.weights[j]);
  194. if (kWeightTolerance > 0f)
  195. {
  196. editableBoneWeight.FilterChannels(kWeightTolerance);
  197. editableBoneWeight.Normalize();
  198. }
  199. mesh.vertexWeights[j] = editableBoneWeight;
  200. }
  201. if (null != sprite.GetCharacterPart())
  202. sprite.DeassociateUnusedBones();
  203. m_SpriteMeshDataController.SortTrianglesByDepth();
  204. }
  205. }
  206. for (var i = 0; i < spriteList.Count; i++)
  207. {
  208. var sd = spriteList[i];
  209. sd.result.Dispose();
  210. sd.indices.Dispose();
  211. sd.edges.Dispose();
  212. sd.vertices.Dispose();
  213. sd.weights.Dispose();
  214. }
  215. if (!cancelProgress)
  216. {
  217. skinningCache.vertexSelection.Clear();
  218. foreach(var sprite in sprites)
  219. skinningCache.events.meshChanged.Invoke(sprite.GetMesh());
  220. }
  221. EditorUtility.ClearProgressBar();
  222. }
  223. if(cancelProgress)
  224. Undo.PerformUndo();
  225. }
  226. protected override void OnActivate()
  227. {
  228. base.OnActivate();
  229. UpdateButton();
  230. Show();
  231. skinningCache.events.selectedSpriteChanged.AddListener(OnSelectedSpriteChanged);
  232. }
  233. protected override void OnDeactivate()
  234. {
  235. base.OnDeactivate();
  236. Hide();
  237. skinningCache.events.selectedSpriteChanged.RemoveListener(OnSelectedSpriteChanged);
  238. }
  239. private void Show()
  240. {
  241. m_GenerateGeometryPanel.SetHiddenFromLayout(false);
  242. }
  243. private void Hide()
  244. {
  245. m_GenerateGeometryPanel.SetHiddenFromLayout(true);
  246. }
  247. private void UpdateButton()
  248. {
  249. var selectedSprite = skinningCache.selectedSprite;
  250. if (selectedSprite == null)
  251. m_GenerateGeometryPanel.SetMode(GenerateGeometryPanel.GenerateMode.Multiple);
  252. else
  253. m_GenerateGeometryPanel.SetMode(GenerateGeometryPanel.GenerateMode.Single);
  254. }
  255. private void OnSelectedSpriteChanged(SpriteCache sprite)
  256. {
  257. UpdateButton();
  258. }
  259. private JobHandle GenerateWeights(SpriteCache sprite, SpriteJobData sd)
  260. {
  261. Debug.Assert(sprite != null);
  262. var mesh = sprite.GetMesh();
  263. Debug.Assert(mesh != null);
  264. using (new DefaultPoseScope(skinningCache.GetEffectiveSkeleton(sprite)))
  265. {
  266. sprite.AssociatePossibleBones();
  267. return GenerateWeights(mesh, sd);
  268. }
  269. }
  270. // todo: Remove. This function seems dubious. Only associate if boneCount is 0 or if boneCount 1 and first bone matches ?
  271. private bool NeedsAssociateBones(CharacterPartCache characterPart)
  272. {
  273. if (characterPart == null)
  274. return false;
  275. var skeleton = characterPart.skinningCache.character.skeleton;
  276. return characterPart.boneCount == 0 ||
  277. (characterPart.boneCount == 1 && characterPart.GetBone(0) == skeleton.GetBone(0));
  278. }
  279. private JobHandle GenerateWeights(MeshCache mesh, SpriteJobData sd)
  280. {
  281. Debug.Assert(mesh != null);
  282. m_SpriteMeshDataController.spriteMeshData = mesh;
  283. var JobHandle = m_SpriteMeshDataController.CalculateWeightsJob(m_WeightGenerator, null, kWeightTolerance, sd);
  284. return JobHandle;
  285. }
  286. protected override void OnGUI()
  287. {
  288. m_MeshPreviewBehaviour.showWeightMap = m_GenerateGeometryPanel.generateWeights;
  289. m_MeshPreviewBehaviour.overlaySelected = m_GenerateGeometryPanel.generateWeights;
  290. skeletonTool.skeletonStyle = SkeletonStyles.Default;
  291. if (m_GenerateGeometryPanel.generateWeights)
  292. skeletonTool.skeletonStyle = SkeletonStyles.WeightMap;
  293. DoSkeletonGUI();
  294. }
  295. }
  296. }