Açıklama Yok
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SpritePostProcess.cs 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. #if ENABLE_ANIMATION_COLLECTION && ENABLE_ANIMATION_BURST
  2. #define ENABLE_ANIMATION_PERFORMANCE
  3. #endif
  4. using System;
  5. using System.Collections.Generic;
  6. using UnityEngine;
  7. using Unity.Collections;
  8. using System.Linq;
  9. using UnityEditor.U2D.Sprites;
  10. using UnityEngine.U2D.Animation;
  11. using UnityEngine.Rendering;
  12. using UnityEngine.U2D;
  13. namespace UnityEditor.U2D.Animation
  14. {
  15. internal class SpritePostProcess : AssetPostprocessor
  16. {
  17. void OnPreprocessAsset()
  18. {
  19. var dataProvider = GetSpriteEditorDataProvider(assetPath);
  20. if (dataProvider != null)
  21. InjectMainSkeletonBones(dataProvider);
  22. }
  23. void OnPostprocessSprites(Texture2D texture, Sprite[] sprites)
  24. {
  25. var ai = GetSpriteEditorDataProvider(assetPath);
  26. if (ai != null)
  27. {
  28. // Injecting these bones a second time, because the Sprite Rect positions
  29. // might have updated between OnPreprocessAsset and OnPostprocessSprites.
  30. InjectMainSkeletonBones(ai);
  31. var definitionScale = CalculateDefinitionScale(texture, ai.GetDataProvider<ITextureDataProvider>());
  32. ai.InitSpriteEditorDataProvider();
  33. PostProcessBoneData(ai, definitionScale, sprites);
  34. PostProcessSpriteMeshData(ai, definitionScale, sprites);
  35. BoneGizmo.instance.ClearSpriteBoneCache();
  36. }
  37. // Get all SpriteSkin in scene and inform them to refresh their cache
  38. RefreshSpriteSkinCache();
  39. }
  40. static void InjectMainSkeletonBones(ISpriteEditorDataProvider dataProvider)
  41. {
  42. var characterDataProvider = dataProvider.GetDataProvider<ICharacterDataProvider>();
  43. var mainSkeletonBonesDataProvider = dataProvider.GetDataProvider<IMainSkeletonDataProvider>();
  44. if (characterDataProvider == null || mainSkeletonBonesDataProvider == null)
  45. return;
  46. var skinningCache = Cache.Create<SkinningCache>();
  47. skinningCache.Create(dataProvider, new SkinningCachePersistentStateTemp());
  48. var skeletonBones = mainSkeletonBonesDataProvider.GetMainSkeletonData().bones ?? new SpriteBone[0];
  49. RemapCharacterPartsToNewBones(skinningCache, skeletonBones);
  50. SkinningModule.ApplyChanges(skinningCache, dataProvider);
  51. }
  52. static void RemapCharacterPartsToNewBones(SkinningCache skinningCache, SpriteBone[] newBones)
  53. {
  54. var skeleton = skinningCache.character.skeleton;
  55. var previousStateBones = skeleton.bones;
  56. var skeletonBones = skinningCache.CreateBoneCacheFromSpriteBones(newBones, 1.0f);
  57. skeleton.SetBones(skeletonBones);
  58. for (var i = 0; i < skinningCache.character.parts.Length; i++)
  59. {
  60. var characterPart = skinningCache.character.parts[i];
  61. var useGuids = !skeletonBones.All(newBone => previousStateBones.All(oldBone => newBone.guid != oldBone.guid));
  62. characterPart.bones = useGuids ?
  63. characterPart.bones.Select(partBone => Array.Find(skeletonBones, skeletonBone => partBone.guid == skeletonBone.guid)).ToArray() :
  64. characterPart.bones.Select(partBone => skeletonBones.ElementAtOrDefault(Array.FindIndex(previousStateBones, oldBone => partBone.guid == oldBone.guid))).ToArray();
  65. var mesh = skinningCache.GetMesh(characterPart.sprite);
  66. if (mesh != null)
  67. mesh.SetCompatibleBoneSet(characterPart.bones);
  68. skinningCache.character.parts[i] = characterPart;
  69. }
  70. }
  71. static void RefreshSpriteSkinCache()
  72. {
  73. #if ENABLE_ANIMATION_PERFORMANCE
  74. var spriteSkins = GameObject.FindObjectsOfType<SpriteSkin>();
  75. foreach (var ss in spriteSkins)
  76. {
  77. ss.ResetSprite();
  78. }
  79. #endif
  80. }
  81. static void CalculateLocaltoWorldMatrix(int i, SpriteRect spriteRect, float definitionScale, float pixelsPerUnit, List<UnityEngine.U2D.SpriteBone> spriteBone, ref UnityEngine.U2D.SpriteBone?[] outpriteBone, ref NativeArray<Matrix4x4> bindPose)
  82. {
  83. if (outpriteBone[i] != null)
  84. return;
  85. UnityEngine.U2D.SpriteBone sp = spriteBone[i];
  86. var isRoot = sp.parentId == -1;
  87. var position = isRoot ? (spriteBone[i].position - Vector3.Scale(spriteRect.rect.size, spriteRect.pivot)) : spriteBone[i].position;
  88. position.z = 0f;
  89. sp.position = position * definitionScale / pixelsPerUnit;
  90. sp.length = spriteBone[i].length * definitionScale / pixelsPerUnit;
  91. outpriteBone[i] = sp;
  92. // Calculate bind poses
  93. var worldPosition = Vector3.zero;
  94. var worldRotation = Quaternion.identity;
  95. if (sp.parentId == -1)
  96. {
  97. worldPosition = sp.position;
  98. worldRotation = sp.rotation;
  99. }
  100. else
  101. {
  102. if (outpriteBone[sp.parentId] == null)
  103. {
  104. CalculateLocaltoWorldMatrix(sp.parentId, spriteRect, definitionScale, pixelsPerUnit, spriteBone, ref outpriteBone, ref bindPose);
  105. }
  106. var parentBindPose = bindPose[sp.parentId];
  107. var invParentBindPose = Matrix4x4.Inverse(parentBindPose);
  108. worldPosition = invParentBindPose.MultiplyPoint(sp.position);
  109. worldRotation = sp.rotation * invParentBindPose.rotation;
  110. }
  111. // Practically Matrix4x4.SetTRInverse
  112. var rot = Quaternion.Inverse(worldRotation);
  113. Matrix4x4 mat = Matrix4x4.identity;
  114. mat = Matrix4x4.Rotate(rot);
  115. mat = mat * Matrix4x4.Translate(-worldPosition);
  116. bindPose[i] = mat;
  117. }
  118. static bool PostProcessBoneData(ISpriteEditorDataProvider spriteDataProvider, float definitionScale, Sprite[] sprites)
  119. {
  120. var boneDataProvider = spriteDataProvider.GetDataProvider<ISpriteBoneDataProvider>();
  121. var textureDataProvider = spriteDataProvider.GetDataProvider<ITextureDataProvider>();
  122. if (sprites == null || sprites.Length == 0 || boneDataProvider == null || textureDataProvider == null)
  123. return false;
  124. var dataChanged = false;
  125. var spriteRects = spriteDataProvider.GetSpriteRects();
  126. foreach (var sprite in sprites)
  127. {
  128. var guid = sprite.GetSpriteID();
  129. {
  130. var spriteBone = boneDataProvider.GetBones(guid);
  131. if (spriteBone == null)
  132. continue;
  133. var spriteBoneCount = spriteBone.Count;
  134. if (spriteBoneCount == 0)
  135. continue;
  136. var spriteRect = spriteRects.First(s => { return s.spriteID == guid; });
  137. var bindPose = new NativeArray<Matrix4x4>(spriteBoneCount, Allocator.Temp);
  138. var outputSpriteBones = new UnityEngine.U2D.SpriteBone ? [spriteBoneCount];
  139. for (int i = 0; i < spriteBoneCount; ++i)
  140. {
  141. CalculateLocaltoWorldMatrix(i, spriteRect, definitionScale, sprite.pixelsPerUnit, spriteBone, ref outputSpriteBones, ref bindPose);
  142. }
  143. sprite.SetBindPoses(bindPose);
  144. sprite.SetBones(outputSpriteBones.Select(x => x.Value).ToArray());
  145. bindPose.Dispose();
  146. dataChanged = true;
  147. }
  148. }
  149. return dataChanged;
  150. }
  151. static bool PostProcessSpriteMeshData(ISpriteEditorDataProvider spriteDataProvider, float definitionScale, Sprite[] sprites)
  152. {
  153. var spriteMeshDataProvider = spriteDataProvider.GetDataProvider<ISpriteMeshDataProvider>();
  154. var boneDataProvider = spriteDataProvider.GetDataProvider<ISpriteBoneDataProvider>();
  155. var textureDataProvider = spriteDataProvider.GetDataProvider<ITextureDataProvider>();
  156. if (sprites == null || sprites.Length == 0 || spriteMeshDataProvider == null || textureDataProvider == null)
  157. return false;
  158. var dataChanged = false;
  159. var spriteRects = spriteDataProvider.GetSpriteRects();
  160. foreach (var sprite in sprites)
  161. {
  162. var guid = sprite.GetSpriteID();
  163. var vertices = spriteMeshDataProvider.GetVertices(guid);
  164. int[] indices = null;
  165. if (vertices.Length > 2)
  166. indices = spriteMeshDataProvider.GetIndices(guid);
  167. if (indices != null && indices.Length > 2 && vertices.Length > 2 )
  168. {
  169. var spriteRect = spriteRects.First(s => { return s.spriteID == guid; });
  170. var spriteBone = boneDataProvider.GetBones(guid);
  171. var hasBones = spriteBone != null && spriteBone.Count > 0;
  172. var hasInvalidWeights = false;
  173. var vertexArray = new NativeArray<Vector3>(vertices.Length, Allocator.Temp);
  174. var boneWeightArray = new NativeArray<BoneWeight>(vertices.Length, Allocator.Temp);
  175. for (int i = 0; i < vertices.Length; ++i)
  176. {
  177. var boneWeight = vertices[i].boneWeight;
  178. vertexArray[i] = (Vector3)(vertices[i].position - Vector2.Scale(spriteRect.rect.size, spriteRect.pivot)) * definitionScale / sprite.pixelsPerUnit;
  179. boneWeightArray[i] = boneWeight;
  180. if (hasBones && !hasInvalidWeights)
  181. {
  182. var sum = boneWeight.weight0 + boneWeight.weight1 + boneWeight.weight2 + boneWeight.weight3;
  183. hasInvalidWeights = sum < 0.999f;
  184. }
  185. }
  186. var indicesArray = new NativeArray<ushort>(indices.Length, Allocator.Temp);
  187. for (int i = 0; i < indices.Length; ++i)
  188. indicesArray[i] = (ushort)indices[i];
  189. sprite.SetVertexCount(vertices.Length);
  190. sprite.SetVertexAttribute<Vector3>(VertexAttribute.Position, vertexArray);
  191. sprite.SetIndices(indicesArray);
  192. sprite.SetVertexAttribute<BoneWeight>(VertexAttribute.BlendWeight, boneWeightArray);
  193. vertexArray.Dispose();
  194. boneWeightArray.Dispose();
  195. indicesArray.Dispose();
  196. // Deformed Sprites require proper Tangent Channels if Lit. Enable Tangent channels.
  197. if (hasBones)
  198. {
  199. var tangentArray = new NativeArray<Vector4>(vertices.Length, Allocator.Temp);
  200. for (int i = 0; i < vertices.Length; ++i)
  201. tangentArray[i] = new Vector4(1.0f, 0.0f, 0, -1.0f);
  202. sprite.SetVertexAttribute<Vector4>(VertexAttribute.Tangent, tangentArray);
  203. tangentArray.Dispose();
  204. }
  205. dataChanged = true;
  206. if (hasBones && hasInvalidWeights)
  207. Debug.LogWarning("Sprite \"" + spriteRect.name + "\" contains bone weights which sum zero or are not normalized. To avoid visual artifacts please consider fixing them.");
  208. }
  209. else
  210. {
  211. var boneWeightArray = new NativeArray<BoneWeight>(sprite.GetVertexCount(), Allocator.Temp);
  212. var defaultBoneWeight = new BoneWeight() { weight0 = 1f };
  213. for (var i = 0; i < boneWeightArray.Length; ++i)
  214. boneWeightArray[i] = defaultBoneWeight;
  215. sprite.SetVertexAttribute<BoneWeight>(VertexAttribute.BlendWeight, boneWeightArray);
  216. }
  217. }
  218. return dataChanged;
  219. }
  220. static float CalculateDefinitionScale(Texture2D texture, ITextureDataProvider dataProvider)
  221. {
  222. float definitionScale = 1;
  223. if (texture != null && dataProvider != null)
  224. {
  225. int actualWidth = 0, actualHeight = 0;
  226. dataProvider.GetTextureActualWidthAndHeight(out actualWidth, out actualHeight);
  227. float definitionScaleW = texture.width / (float)actualWidth;
  228. float definitionScaleH = texture.height / (float)actualHeight;
  229. definitionScale = Mathf.Min(definitionScaleW, definitionScaleH);
  230. }
  231. return definitionScale;
  232. }
  233. static ISpriteEditorDataProvider GetSpriteEditorDataProvider(string assetPath)
  234. {
  235. var dataProviderFactories = new SpriteDataProviderFactories();
  236. dataProviderFactories.Init();
  237. return dataProviderFactories.GetSpriteEditorDataProviderFromObject(AssetImporter.GetAtPath(assetPath));
  238. }
  239. internal class SkinningCachePersistentStateTemp : ISkinningCachePersistentState
  240. {
  241. private string _lastSpriteId;
  242. private Tools _lastUsedTool;
  243. private List<int> _lastBoneSelectionIds = null;
  244. private Texture2D _lastTexture = null;
  245. private SerializableDictionary<int, BonePose> _lastPreviewPose = null;
  246. private SerializableDictionary<int, bool> _lastBoneVisibility = null;
  247. private SerializableDictionary<int, bool> _lastBoneExpansion = null;
  248. private SerializableDictionary<string, bool> _lastSpriteVisibility = null;
  249. private SerializableDictionary<int, bool> _lastGroupVisibility = null;
  250. private SkinningMode _lastMode;
  251. private bool _lastVisibilityToolActive;
  252. private int _lastVisibilityToolIndex;
  253. private IndexedSelection _lastVertexSelection = null;
  254. private float _lastBrushSize;
  255. private float _lastBrushHardness;
  256. private float _lastBrushStep;
  257. string ISkinningCachePersistentState.lastSpriteId
  258. {
  259. get => _lastSpriteId;
  260. set => _lastSpriteId = value;
  261. }
  262. Tools ISkinningCachePersistentState.lastUsedTool
  263. {
  264. get => _lastUsedTool;
  265. set => _lastUsedTool = value;
  266. }
  267. List<int> ISkinningCachePersistentState.lastBoneSelectionIds => _lastBoneSelectionIds;
  268. Texture2D ISkinningCachePersistentState.lastTexture
  269. {
  270. get => _lastTexture;
  271. set => _lastTexture = value;
  272. }
  273. SerializableDictionary<int, BonePose> ISkinningCachePersistentState.lastPreviewPose => _lastPreviewPose;
  274. SerializableDictionary<int, bool> ISkinningCachePersistentState.lastBoneVisibility => _lastBoneVisibility;
  275. SerializableDictionary<int, bool> ISkinningCachePersistentState.lastBoneExpansion => _lastBoneExpansion;
  276. SerializableDictionary<string, bool> ISkinningCachePersistentState.lastSpriteVisibility => _lastSpriteVisibility;
  277. SerializableDictionary<int, bool> ISkinningCachePersistentState.lastGroupVisibility => _lastGroupVisibility;
  278. SkinningMode ISkinningCachePersistentState.lastMode
  279. {
  280. get => _lastMode;
  281. set => _lastMode = value;
  282. }
  283. bool ISkinningCachePersistentState.lastVisibilityToolActive
  284. {
  285. get => _lastVisibilityToolActive;
  286. set => _lastVisibilityToolActive = value;
  287. }
  288. int ISkinningCachePersistentState.lastVisibilityToolIndex
  289. {
  290. get => _lastVisibilityToolIndex;
  291. set => _lastVisibilityToolIndex = value;
  292. }
  293. IndexedSelection ISkinningCachePersistentState.lastVertexSelection => _lastVertexSelection;
  294. float ISkinningCachePersistentState.lastBrushSize
  295. {
  296. get => _lastBrushSize;
  297. set => _lastBrushSize = value;
  298. }
  299. float ISkinningCachePersistentState.lastBrushHardness
  300. {
  301. get => _lastBrushHardness;
  302. set => _lastBrushHardness = value;
  303. }
  304. float ISkinningCachePersistentState.lastBrushStep
  305. {
  306. get => _lastBrushStep;
  307. set => _lastBrushStep = value;
  308. }
  309. }
  310. }
  311. }