설명 없음
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.

BaseDeformationSystem.cs 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. using System;
  2. using System.Collections.Generic;
  3. using Unity.Collections;
  4. using Unity.Collections.LowLevel.Unsafe;
  5. using Unity.Jobs;
  6. using Unity.Mathematics;
  7. using Unity.Profiling;
  8. using UnityEngine.U2D.Common;
  9. namespace UnityEngine.U2D.Animation
  10. {
  11. internal abstract class BaseDeformationSystem
  12. {
  13. protected static class Profiling
  14. {
  15. public static readonly ProfilerMarker transformAccessJob = new ProfilerMarker("BaseDeformationSystem.TransformAccessJob");
  16. public static readonly ProfilerMarker getSpriteSkinBatchData = new ProfilerMarker("BaseDeformationSystem.GetSpriteSkinBatchData");
  17. public static readonly ProfilerMarker scheduleJobs = new ProfilerMarker("BaseDeformationSystem.ScheduleJobs");
  18. public static readonly ProfilerMarker setBatchDeformableBufferAndLocalAABB = new ProfilerMarker("BaseDeformationSystem.SetBatchDeformableBufferAndLocalAABB");
  19. public static readonly ProfilerMarker setBoneTransformsArray = new ProfilerMarker("BaseDeformationSystem.SetBoneTransformsArray");
  20. }
  21. public abstract DeformationMethods deformationMethod { get; }
  22. protected int m_ObjectId;
  23. protected readonly HashSet<SpriteSkin> m_SpriteSkins = new HashSet<SpriteSkin>();
  24. protected SpriteRenderer[] m_SpriteRenderers = new SpriteRenderer[0];
  25. readonly HashSet<SpriteSkin> m_SpriteSkinsToAdd = new HashSet<SpriteSkin>();
  26. readonly HashSet<SpriteSkin> m_SpriteSkinsToRemove = new HashSet<SpriteSkin>();
  27. readonly List<int> m_TransformIdsToRemove = new List<int>();
  28. protected NativeByteArray m_DeformedVerticesBuffer;
  29. protected NativeArray<float4x4> m_FinalBoneTransforms;
  30. protected NativeArray<bool> m_IsSpriteSkinActiveForDeform;
  31. protected NativeArray<SpriteSkinData> m_SpriteSkinData;
  32. protected NativeArray<PerSkinJobData> m_PerSkinJobData;
  33. protected NativeArray<Bounds> m_BoundsData;
  34. protected NativeArray<IntPtr> m_Buffers;
  35. protected NativeArray<int> m_BufferSizes;
  36. protected NativeArray<IntPtr> m_BoneTransformBuffers;
  37. protected NativeArray<int2> m_BoneLookupData;
  38. protected NativeArray<int2> m_VertexLookupData;
  39. protected NativeArray<PerSkinJobData> m_SkinBatchArray;
  40. TransformAccessJob m_LocalToWorldTransformAccessJob;
  41. TransformAccessJob m_WorldToLocalTransformAccessJob;
  42. protected JobHandle m_DeformJobHandle;
  43. internal void RemoveBoneTransforms(SpriteSkin spriteSkin)
  44. {
  45. if (!m_SpriteSkins.Contains(spriteSkin))
  46. return;
  47. m_LocalToWorldTransformAccessJob.RemoveTransformById(spriteSkin.rootBoneTransformId);
  48. var boneTransforms = spriteSkin.boneTransformId;
  49. if (boneTransforms == default || !boneTransforms.IsCreated)
  50. return;
  51. for (var i = 0; i < boneTransforms.Length; ++i)
  52. m_LocalToWorldTransformAccessJob.RemoveTransformById(boneTransforms[i]);
  53. }
  54. internal void AddBoneTransforms(SpriteSkin spriteSkin)
  55. {
  56. if (!m_SpriteSkins.Contains(spriteSkin))
  57. return;
  58. m_LocalToWorldTransformAccessJob.AddTransform(spriteSkin.rootBone);
  59. if (spriteSkin.boneTransforms != null)
  60. {
  61. foreach (var t in spriteSkin.boneTransforms)
  62. {
  63. if (t != null)
  64. m_LocalToWorldTransformAccessJob.AddTransform(t);
  65. }
  66. }
  67. }
  68. internal virtual void UpdateMaterial(SpriteSkin spriteSkin) { }
  69. internal virtual bool AddSpriteSkin(SpriteSkin spriteSkin)
  70. {
  71. if (!m_SpriteSkins.Contains(spriteSkin) && !m_SpriteSkinsToAdd.Contains(spriteSkin))
  72. {
  73. m_SpriteSkinsToAdd.Add(spriteSkin);
  74. return true;
  75. }
  76. if (m_SpriteSkinsToRemove.Contains(spriteSkin))
  77. {
  78. m_SpriteSkinsToAdd.Add(spriteSkin);
  79. return true;
  80. }
  81. return false;
  82. }
  83. internal void CopyToSpriteSkinData(SpriteSkin spriteSkin)
  84. {
  85. CopyToSpriteSkinDataAtIndex(spriteSkin, spriteSkin.dataIndex);
  86. }
  87. void CopyToSpriteSkinDataAtIndex(SpriteSkin spriteSkin, int index)
  88. {
  89. if (index < 0 || index >= m_SpriteSkins.Count)
  90. return;
  91. if (!m_SpriteSkinData.IsCreated)
  92. return;
  93. var spriteSkinData = default(SpriteSkinData);
  94. spriteSkin.CopyToSpriteSkinData(ref spriteSkinData, index);
  95. m_SpriteSkinData[index] = spriteSkinData;
  96. m_SpriteRenderers[index] = spriteSkin.spriteRenderer;
  97. }
  98. internal void RemoveSpriteSkin(SpriteSkin spriteSkin)
  99. {
  100. if (spriteSkin == null)
  101. return;
  102. if (m_SpriteSkins.Contains(spriteSkin) && !m_SpriteSkinsToRemove.Contains(spriteSkin))
  103. {
  104. m_SpriteSkinsToRemove.Add(spriteSkin);
  105. m_TransformIdsToRemove.Add(spriteSkin.transform.GetInstanceID());
  106. }
  107. if (m_SpriteSkinsToAdd.Contains(spriteSkin))
  108. m_SpriteSkinsToAdd.Remove(spriteSkin);
  109. RemoveBoneTransforms(spriteSkin);
  110. }
  111. internal HashSet<SpriteSkin> GetSpriteSkins()
  112. {
  113. return m_SpriteSkins;
  114. }
  115. internal void Initialize(int objectId)
  116. {
  117. m_ObjectId = objectId;
  118. if (m_LocalToWorldTransformAccessJob == null)
  119. m_LocalToWorldTransformAccessJob = new TransformAccessJob();
  120. if (m_WorldToLocalTransformAccessJob == null)
  121. m_WorldToLocalTransformAccessJob = new TransformAccessJob();
  122. InitializeArrays();
  123. BatchRemoveSpriteSkins();
  124. BatchAddSpriteSkins();
  125. // Initialise all existing SpriteSkins as execution order is indeterminate
  126. var count = 0;
  127. foreach (var spriteSkin in m_SpriteSkins)
  128. {
  129. CopyToSpriteSkinDataAtIndex(spriteSkin, count++);
  130. }
  131. }
  132. protected virtual void InitializeArrays()
  133. {
  134. const int startingCount = 0;
  135. m_FinalBoneTransforms = new NativeArray<float4x4>(startingCount, Allocator.Persistent);
  136. m_BoneLookupData = new NativeArray<int2>(startingCount, Allocator.Persistent);
  137. m_VertexLookupData = new NativeArray<int2>(startingCount, Allocator.Persistent);
  138. m_SkinBatchArray = new NativeArray<PerSkinJobData>(startingCount, Allocator.Persistent);
  139. m_IsSpriteSkinActiveForDeform = new NativeArray<bool>(startingCount, Allocator.Persistent);
  140. m_PerSkinJobData = new NativeArray<PerSkinJobData>(startingCount, Allocator.Persistent);
  141. m_SpriteSkinData = new NativeArray<SpriteSkinData>(startingCount, Allocator.Persistent);
  142. m_BoundsData = new NativeArray<Bounds>(startingCount, Allocator.Persistent);
  143. m_Buffers = new NativeArray<IntPtr>(startingCount, Allocator.Persistent);
  144. m_BufferSizes = new NativeArray<int>(startingCount, Allocator.Persistent);
  145. }
  146. protected void BatchRemoveSpriteSkins()
  147. {
  148. var spritesToRemoveCount = m_SpriteSkinsToRemove.Count;
  149. if (spritesToRemoveCount == 0)
  150. return;
  151. m_WorldToLocalTransformAccessJob.RemoveTransformsByIds(m_TransformIdsToRemove);
  152. var updatedCount = Math.Max(m_SpriteSkins.Count - spritesToRemoveCount, 0);
  153. if (updatedCount == 0)
  154. {
  155. m_SpriteSkins.Clear();
  156. }
  157. else
  158. {
  159. foreach (var spriteSkin in m_SpriteSkinsToRemove)
  160. m_SpriteSkins.Remove(spriteSkin);
  161. }
  162. var count = 0;
  163. foreach (var spriteSkin in m_SpriteSkins)
  164. CopyToSpriteSkinDataAtIndex(spriteSkin, count++);
  165. Array.Resize(ref m_SpriteRenderers, updatedCount);
  166. ResizeAndCopyArrays(updatedCount);
  167. m_TransformIdsToRemove.Clear();
  168. m_SpriteSkinsToRemove.Clear();
  169. }
  170. protected void BatchAddSpriteSkins()
  171. {
  172. if (m_SpriteSkinsToAdd.Count == 0)
  173. return;
  174. var updatedCount = m_SpriteSkins.Count + m_SpriteSkinsToAdd.Count;
  175. Array.Resize(ref m_SpriteRenderers, updatedCount);
  176. if (m_IsSpriteSkinActiveForDeform.IsCreated)
  177. ResizeAndCopyArrays(updatedCount);
  178. foreach (var spriteSkin in m_SpriteSkinsToAdd)
  179. {
  180. if (m_SpriteSkins.Contains(spriteSkin))
  181. {
  182. Debug.LogError($"Skin already exists! Name={spriteSkin.name}");
  183. continue;
  184. }
  185. m_SpriteSkins.Add(spriteSkin);
  186. UpdateMaterial(spriteSkin);
  187. var count = m_SpriteSkins.Count;
  188. m_SpriteRenderers[count - 1] = spriteSkin.spriteRenderer;
  189. m_WorldToLocalTransformAccessJob.AddTransform(spriteSkin.transform);
  190. if (m_IsSpriteSkinActiveForDeform.IsCreated)
  191. {
  192. AddBoneTransforms(spriteSkin);
  193. CopyToSpriteSkinDataAtIndex(spriteSkin, count - 1);
  194. }
  195. }
  196. m_SpriteSkinsToAdd.Clear();
  197. }
  198. protected virtual void ResizeAndCopyArrays(int updatedCount)
  199. {
  200. NativeArrayHelpers.ResizeAndCopyIfNeeded(ref m_IsSpriteSkinActiveForDeform, updatedCount);
  201. NativeArrayHelpers.ResizeAndCopyIfNeeded(ref m_PerSkinJobData, updatedCount);
  202. NativeArrayHelpers.ResizeAndCopyIfNeeded(ref m_Buffers, updatedCount);
  203. NativeArrayHelpers.ResizeAndCopyIfNeeded(ref m_BufferSizes, updatedCount);
  204. NativeArrayHelpers.ResizeAndCopyIfNeeded(ref m_SpriteSkinData, updatedCount);
  205. NativeArrayHelpers.ResizeAndCopyIfNeeded(ref m_BoundsData, updatedCount);
  206. }
  207. internal virtual void Cleanup()
  208. {
  209. m_DeformJobHandle.Complete();
  210. m_SpriteSkins.Clear();
  211. m_SpriteRenderers = new SpriteRenderer[0];
  212. BufferManager.instance.ReturnBuffer(m_ObjectId);
  213. m_IsSpriteSkinActiveForDeform.DisposeIfCreated();
  214. m_PerSkinJobData.DisposeIfCreated();
  215. m_Buffers.DisposeIfCreated();
  216. m_BufferSizes.DisposeIfCreated();
  217. m_SpriteSkinData.DisposeIfCreated();
  218. m_BoneLookupData.DisposeIfCreated();
  219. m_VertexLookupData.DisposeIfCreated();
  220. m_SkinBatchArray.DisposeIfCreated();
  221. m_FinalBoneTransforms.DisposeIfCreated();
  222. m_BoundsData.DisposeIfCreated();
  223. m_LocalToWorldTransformAccessJob.Destroy();
  224. m_WorldToLocalTransformAccessJob.Destroy();
  225. }
  226. internal abstract void Update();
  227. protected void PrepareDataForDeformation(out JobHandle localToWorldJobHandle, out JobHandle worldToLocalJobHandle)
  228. {
  229. ValidateSpriteSkinData();
  230. using (Profiling.transformAccessJob.Auto())
  231. {
  232. localToWorldJobHandle = m_LocalToWorldTransformAccessJob.StartLocalToWorldJob();
  233. worldToLocalJobHandle = m_WorldToLocalTransformAccessJob.StartWorldToLocalJob();
  234. }
  235. using (Profiling.getSpriteSkinBatchData.Auto())
  236. {
  237. NativeArrayHelpers.ResizeIfNeeded(ref m_SkinBatchArray, 1);
  238. var fillPerSkinJobSingleThread = new FillPerSkinJobSingleThread()
  239. {
  240. isSpriteSkinValidForDeformArray = m_IsSpriteSkinActiveForDeform,
  241. combinedSkinBatchArray = m_SkinBatchArray,
  242. spriteSkinDataArray = m_SpriteSkinData,
  243. perSkinJobDataArray = m_PerSkinJobData,
  244. };
  245. fillPerSkinJobSingleThread.Run();
  246. }
  247. }
  248. void ValidateSpriteSkinData()
  249. {
  250. var count = 0;
  251. foreach (var spriteSkin in m_SpriteSkins)
  252. {
  253. var i = count++;
  254. m_IsSpriteSkinActiveForDeform[i] = spriteSkin.BatchValidate();
  255. if (m_IsSpriteSkinActiveForDeform[i] && spriteSkin.NeedToUpdateDeformationCache())
  256. {
  257. CopyToSpriteSkinDataAtIndex(spriteSkin, i);
  258. }
  259. }
  260. }
  261. protected bool GotVerticesToDeform(out int vertexBufferSize)
  262. {
  263. vertexBufferSize = m_SkinBatchArray[0].deformVerticesStartPos;
  264. return vertexBufferSize > 0;
  265. }
  266. protected JobHandle SchedulePrepareJob(int batchCount)
  267. {
  268. var prepareJob = new PrepareDeformJob
  269. {
  270. batchDataSize = batchCount,
  271. perSkinJobData = m_PerSkinJobData,
  272. boneLookupData = m_BoneLookupData,
  273. vertexLookupData = m_VertexLookupData
  274. };
  275. return prepareJob.Schedule();
  276. }
  277. protected JobHandle ScheduleBoneJobBatched(JobHandle jobHandle, PerSkinJobData skinBatch)
  278. {
  279. var boneJobBatched = new BoneDeformBatchedJob()
  280. {
  281. boneTransform = m_LocalToWorldTransformAccessJob.transformMatrix,
  282. rootTransform = m_WorldToLocalTransformAccessJob.transformMatrix,
  283. spriteSkinData = m_SpriteSkinData,
  284. boneLookupData = m_BoneLookupData,
  285. finalBoneTransforms = m_FinalBoneTransforms,
  286. rootTransformIndex = m_WorldToLocalTransformAccessJob.transformData,
  287. boneTransformIndex = m_LocalToWorldTransformAccessJob.transformData
  288. };
  289. jobHandle = boneJobBatched.Schedule(skinBatch.bindPosesIndex.y, 8, jobHandle);
  290. return jobHandle;
  291. }
  292. protected JobHandle ScheduleSkinDeformBatchedJob(JobHandle jobHandle, PerSkinJobData skinBatch)
  293. {
  294. var skinJobBatched = new SkinDeformBatchedJob()
  295. {
  296. vertices = m_DeformedVerticesBuffer.array,
  297. vertexLookupData = m_VertexLookupData,
  298. spriteSkinData = m_SpriteSkinData,
  299. perSkinJobData = m_PerSkinJobData,
  300. finalBoneTransforms = m_FinalBoneTransforms,
  301. };
  302. return skinJobBatched.Schedule(skinBatch.verticesIndex.y, 16, jobHandle);
  303. }
  304. protected unsafe JobHandle ScheduleCopySpriteRendererBuffersJob(JobHandle jobHandle, int batchCount)
  305. {
  306. var copySpriteRendererBuffersJob = new CopySpriteRendererBuffersJob()
  307. {
  308. isSpriteSkinValidForDeformArray = m_IsSpriteSkinActiveForDeform,
  309. spriteSkinData = m_SpriteSkinData,
  310. ptrVertices = (IntPtr)NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(m_DeformedVerticesBuffer.array),
  311. buffers = m_Buffers,
  312. bufferSizes = m_BufferSizes,
  313. };
  314. return copySpriteRendererBuffersJob.Schedule(batchCount, 16, jobHandle);
  315. }
  316. protected JobHandle ScheduleCalculateSpriteSkinAABBJob(JobHandle jobHandle, int batchCount)
  317. {
  318. var updateBoundJob = new CalculateSpriteSkinAABBJob
  319. {
  320. vertices = m_DeformedVerticesBuffer.array,
  321. isSpriteSkinValidForDeformArray = m_IsSpriteSkinActiveForDeform,
  322. spriteSkinData = m_SpriteSkinData,
  323. bounds = m_BoundsData,
  324. };
  325. return updateBoundJob.Schedule(batchCount, 4, jobHandle);
  326. }
  327. protected void DeactivateDeformableBuffers()
  328. {
  329. for (var i = 0; i < m_IsSpriteSkinActiveForDeform.Length; ++i)
  330. {
  331. if (m_IsSpriteSkinActiveForDeform[i] || InternalEngineBridge.IsUsingDeformableBuffer(m_SpriteRenderers[i], IntPtr.Zero))
  332. continue;
  333. m_SpriteRenderers[i].DeactivateDeformableBuffer();
  334. }
  335. }
  336. internal bool IsSpriteSkinActiveForDeformation(SpriteSkin spriteSkin)
  337. {
  338. return m_IsSpriteSkinActiveForDeform[spriteSkin.dataIndex];
  339. }
  340. internal unsafe NativeArray<byte> GetDeformableBufferForSpriteSkin(SpriteSkin spriteSkin)
  341. {
  342. if (!m_SpriteSkins.Contains(spriteSkin))
  343. return default;
  344. if (!m_DeformJobHandle.IsCompleted)
  345. m_DeformJobHandle.Complete();
  346. var skinData = m_SpriteSkinData[spriteSkin.dataIndex];
  347. if (skinData.deformVerticesStartPos < 0)
  348. return default;
  349. var vertexBufferLength = skinData.spriteVertexCount * skinData.spriteVertexStreamSize;
  350. var ptrVertices = (byte*)m_DeformedVerticesBuffer.array.GetUnsafeReadOnlyPtr();
  351. ptrVertices += skinData.deformVerticesStartPos;
  352. var buffer = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<byte>(ptrVertices, vertexBufferLength, Allocator.None);
  353. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  354. NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref buffer, NativeArrayUnsafeUtility.GetAtomicSafetyHandle(m_DeformedVerticesBuffer.array));
  355. #endif
  356. return buffer;
  357. }
  358. #if UNITY_INCLUDE_TESTS
  359. internal TransformAccessJob GetWorldToLocalTransformAccessJob() => m_WorldToLocalTransformAccessJob;
  360. internal TransformAccessJob GetLocalToWorldTransformAccessJob() => m_LocalToWorldTransformAccessJob;
  361. #endif
  362. }
  363. }