Nenhuma descrição
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

SpritePostProcess.cs 17KB

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