Нет описания
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

SpriteSkinUtility.cs 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. using System;
  2. using Unity.Burst;
  3. using Unity.Collections;
  4. using Unity.Mathematics;
  5. using Unity.Collections.LowLevel.Unsafe;
  6. using UnityEngine.U2D.Common;
  7. namespace UnityEngine.U2D.Animation
  8. {
  9. internal enum SpriteSkinValidationResult
  10. {
  11. SpriteNotFound,
  12. SpriteHasNoSkinningInformation,
  13. SpriteHasNoWeights,
  14. RootTransformNotFound,
  15. InvalidTransformArray,
  16. InvalidTransformArrayLength,
  17. TransformArrayContainsNull,
  18. RootNotFoundInTransformArray,
  19. InvalidBoneWeights,
  20. Ready
  21. }
  22. internal class NativeByteArray
  23. {
  24. public int Length => array.Length;
  25. public bool IsCreated => array.IsCreated;
  26. public byte this[int index] => array[index];
  27. public NativeArray<byte> array
  28. { get; }
  29. public NativeByteArray(NativeArray<byte> array)
  30. {
  31. this.array = array;
  32. }
  33. public void Dispose() => array.Dispose();
  34. }
  35. internal static class SpriteSkinUtility
  36. {
  37. internal static SpriteSkinValidationResult Validate(this SpriteSkin spriteSkin)
  38. {
  39. if (spriteSkin.spriteRenderer.sprite == null)
  40. return SpriteSkinValidationResult.SpriteNotFound;
  41. var bindPoses = spriteSkin.spriteRenderer.sprite.GetBindPoses();
  42. var bindPoseCount = bindPoses.Length;
  43. if (bindPoseCount == 0)
  44. return SpriteSkinValidationResult.SpriteHasNoSkinningInformation;
  45. if (spriteSkin.rootBone == null)
  46. return SpriteSkinValidationResult.RootTransformNotFound;
  47. if (spriteSkin.boneTransforms == null)
  48. return SpriteSkinValidationResult.InvalidTransformArray;
  49. if (bindPoseCount != spriteSkin.boneTransforms.Length)
  50. return SpriteSkinValidationResult.InvalidTransformArrayLength;
  51. var rootFound = false;
  52. foreach (var boneTransform in spriteSkin.boneTransforms)
  53. {
  54. if (boneTransform == null)
  55. return SpriteSkinValidationResult.TransformArrayContainsNull;
  56. if (boneTransform == spriteSkin.rootBone)
  57. rootFound = true;
  58. }
  59. if (!rootFound)
  60. return SpriteSkinValidationResult.RootNotFoundInTransformArray;
  61. var boneWeights = spriteSkin.sprite.GetVertexAttribute<BoneWeight>(UnityEngine.Rendering.VertexAttribute.BlendWeight);
  62. if (!BurstedSpriteSkinUtilities.ValidateBoneWeights(in boneWeights, bindPoseCount))
  63. return SpriteSkinValidationResult.InvalidBoneWeights;
  64. return SpriteSkinValidationResult.Ready;
  65. }
  66. internal static void CreateBoneHierarchy(this SpriteSkin spriteSkin)
  67. {
  68. if (spriteSkin.spriteRenderer.sprite == null)
  69. throw new InvalidOperationException("SpriteRenderer has no Sprite set");
  70. var spriteBones = spriteSkin.spriteRenderer.sprite.GetBones();
  71. var transforms = new Transform[spriteBones.Length];
  72. Transform root = null;
  73. for (int i = 0; i < spriteBones.Length; ++i)
  74. {
  75. CreateGameObject(i, spriteBones, transforms, spriteSkin.transform);
  76. if (spriteBones[i].parentId < 0 && root == null)
  77. root = transforms[i];
  78. }
  79. spriteSkin.rootBone = root;
  80. spriteSkin.boneTransforms = transforms;
  81. }
  82. internal static int GetVertexStreamSize(this Sprite sprite)
  83. {
  84. int vertexStreamSize = 12;
  85. if (sprite.HasVertexAttribute(Rendering.VertexAttribute.Normal))
  86. vertexStreamSize = vertexStreamSize + 12;
  87. if (sprite.HasVertexAttribute(Rendering.VertexAttribute.Tangent))
  88. vertexStreamSize = vertexStreamSize + 16;
  89. return vertexStreamSize;
  90. }
  91. internal static int GetVertexStreamOffset(this Sprite sprite, Rendering.VertexAttribute channel )
  92. {
  93. bool hasPosition = sprite.HasVertexAttribute(Rendering.VertexAttribute.Position);
  94. bool hasNormals = sprite.HasVertexAttribute(Rendering.VertexAttribute.Normal);
  95. bool hasTangents = sprite.HasVertexAttribute(Rendering.VertexAttribute.Tangent);
  96. switch(channel)
  97. {
  98. case Rendering.VertexAttribute.Position:
  99. return hasPosition ? 0 : -1;
  100. case Rendering.VertexAttribute.Normal:
  101. return hasNormals ? 12 : -1;
  102. case Rendering.VertexAttribute.Tangent:
  103. return hasTangents ? (hasNormals ? 24 : 12) : -1;
  104. }
  105. return -1;
  106. }
  107. private static void CreateGameObject(int index, SpriteBone[] spriteBones, Transform[] transforms, Transform root)
  108. {
  109. if (transforms[index] == null)
  110. {
  111. var spriteBone = spriteBones[index];
  112. if (spriteBone.parentId >= 0)
  113. CreateGameObject(spriteBone.parentId, spriteBones, transforms, root);
  114. var go = new GameObject(spriteBone.name);
  115. var transform = go.transform;
  116. if (spriteBone.parentId >= 0)
  117. transform.SetParent(transforms[spriteBone.parentId]);
  118. else
  119. transform.SetParent(root);
  120. transform.localPosition = spriteBone.position;
  121. transform.localRotation = spriteBone.rotation;
  122. transform.localScale = Vector3.one;
  123. transforms[index] = transform;
  124. }
  125. }
  126. internal static void ResetBindPose(this SpriteSkin spriteSkin)
  127. {
  128. if (!spriteSkin.isValid)
  129. throw new InvalidOperationException("SpriteSkin is not valid");
  130. var spriteBones = spriteSkin.spriteRenderer.sprite.GetBones();
  131. var boneTransforms = spriteSkin.boneTransforms;
  132. for (int i = 0; i < boneTransforms.Length; ++i)
  133. {
  134. var boneTransform = boneTransforms[i];
  135. var spriteBone = spriteBones[i];
  136. if (spriteBone.parentId != -1)
  137. {
  138. boneTransform.localPosition = spriteBone.position;
  139. boneTransform.localRotation = spriteBone.rotation;
  140. boneTransform.localScale = Vector3.one;
  141. }
  142. }
  143. }
  144. private static int GetHash(Matrix4x4 matrix)
  145. {
  146. unsafe
  147. {
  148. uint* b = (uint*)&matrix;
  149. {
  150. var c = (char*)b;
  151. return (int)math.hash(c, 16 * sizeof(float));
  152. }
  153. }
  154. }
  155. internal static int CalculateTransformHash(this SpriteSkin spriteSkin)
  156. {
  157. int bits = 0;
  158. int boneTransformHash = GetHash(spriteSkin.transform.localToWorldMatrix) >> bits;
  159. bits++;
  160. foreach (var transform in spriteSkin.boneTransforms)
  161. {
  162. boneTransformHash ^= GetHash(transform.localToWorldMatrix) >> bits;
  163. bits = (bits + 1) % 8;
  164. }
  165. return boneTransformHash;
  166. }
  167. internal unsafe static void Deform(Sprite sprite, Matrix4x4 rootInv, NativeSlice<Vector3> vertices, NativeSlice<Vector4> tangents, NativeSlice<BoneWeight> boneWeights, NativeArray<Matrix4x4> boneTransforms, NativeSlice<Matrix4x4> bindPoses, NativeArray<byte> deformableVertices)
  168. {
  169. var verticesFloat3 = vertices.SliceWithStride<float3>();
  170. var tangentsFloat4 = tangents.SliceWithStride<float4>();
  171. var bindPosesFloat4x4 = bindPoses.SliceWithStride<float4x4>();
  172. var spriteVertexCount = sprite.GetVertexCount();
  173. var spriteVertexStreamSize = sprite.GetVertexStreamSize();
  174. var boneTransformsFloat4x4 = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<float4x4>(boneTransforms.GetUnsafePtr(), boneTransforms.Length, Allocator.None);
  175. byte* deformedPosOffset = (byte*)NativeArrayUnsafeUtility.GetUnsafePtr(deformableVertices);
  176. NativeSlice<float3> deformableVerticesFloat3 = NativeSliceUnsafeUtility.ConvertExistingDataToNativeSlice<float3>(deformedPosOffset, spriteVertexStreamSize, spriteVertexCount);
  177. NativeSlice<float4> deformableTangentsFloat4 = NativeSliceUnsafeUtility.ConvertExistingDataToNativeSlice<float4>(deformedPosOffset, spriteVertexStreamSize, 1); // Just Dummy.
  178. if (sprite.HasVertexAttribute(Rendering.VertexAttribute.Tangent))
  179. {
  180. byte* deformedTanOffset = deformedPosOffset + sprite.GetVertexStreamOffset(Rendering.VertexAttribute.Tangent);
  181. deformableTangentsFloat4 = NativeSliceUnsafeUtility.ConvertExistingDataToNativeSlice<float4>(deformedTanOffset, spriteVertexStreamSize, spriteVertexCount);
  182. }
  183. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  184. var handle1 = CreateSafetyChecks<float4x4>(ref boneTransformsFloat4x4);
  185. var handle2 = CreateSafetyChecks<float3>(ref deformableVerticesFloat3);
  186. var handle3 = CreateSafetyChecks<float4>(ref deformableTangentsFloat4);
  187. #endif
  188. if (sprite.HasVertexAttribute(Rendering.VertexAttribute.Tangent))
  189. Deform(rootInv, verticesFloat3, tangentsFloat4, boneWeights, boneTransformsFloat4x4, bindPosesFloat4x4, deformableVerticesFloat3, deformableTangentsFloat4);
  190. else
  191. Deform(rootInv, verticesFloat3, boneWeights, boneTransformsFloat4x4, bindPosesFloat4x4, deformableVerticesFloat3);
  192. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  193. DisposeSafetyChecks(handle1);
  194. DisposeSafetyChecks(handle2);
  195. DisposeSafetyChecks(handle3);
  196. #endif
  197. }
  198. internal static void Deform(float4x4 rootInv, NativeSlice<float3> vertices, NativeSlice<BoneWeight> boneWeights, NativeArray<float4x4> boneTransforms, NativeSlice<float4x4> bindPoses, NativeSlice<float3> deformed)
  199. {
  200. if (boneTransforms.Length == 0)
  201. return;
  202. for (var i = 0; i < boneTransforms.Length; i++)
  203. {
  204. var bindPoseMat = bindPoses[i];
  205. var boneTransformMat = boneTransforms[i];
  206. boneTransforms[i] = math.mul(rootInv, math.mul(boneTransformMat, bindPoseMat));
  207. }
  208. for (var i = 0; i < vertices.Length; i++)
  209. {
  210. var bone0 = boneWeights[i].boneIndex0;
  211. var bone1 = boneWeights[i].boneIndex1;
  212. var bone2 = boneWeights[i].boneIndex2;
  213. var bone3 = boneWeights[i].boneIndex3;
  214. var vertex = vertices[i];
  215. deformed[i] =
  216. math.transform(boneTransforms[bone0], vertex) * boneWeights[i].weight0 +
  217. math.transform(boneTransforms[bone1], vertex) * boneWeights[i].weight1 +
  218. math.transform(boneTransforms[bone2], vertex) * boneWeights[i].weight2 +
  219. math.transform(boneTransforms[bone3], vertex) * boneWeights[i].weight3;
  220. }
  221. }
  222. internal static void Deform(float4x4 rootInv, NativeSlice<float3> vertices, NativeSlice<float4> tangents, NativeSlice<BoneWeight> boneWeights, NativeArray<float4x4> boneTransforms, NativeSlice<float4x4> bindPoses, NativeSlice<float3> deformed, NativeSlice<float4> deformedTangents)
  223. {
  224. if(boneTransforms.Length == 0)
  225. return;
  226. for (var i = 0; i < boneTransforms.Length; i++)
  227. {
  228. var bindPoseMat = bindPoses[i];
  229. var boneTransformMat = boneTransforms[i];
  230. boneTransforms[i] = math.mul(rootInv, math.mul(boneTransformMat, bindPoseMat));
  231. }
  232. for (var i = 0; i < vertices.Length; i++)
  233. {
  234. var bone0 = boneWeights[i].boneIndex0;
  235. var bone1 = boneWeights[i].boneIndex1;
  236. var bone2 = boneWeights[i].boneIndex2;
  237. var bone3 = boneWeights[i].boneIndex3;
  238. var vertex = vertices[i];
  239. deformed[i] =
  240. math.transform(boneTransforms[bone0], vertex) * boneWeights[i].weight0 +
  241. math.transform(boneTransforms[bone1], vertex) * boneWeights[i].weight1 +
  242. math.transform(boneTransforms[bone2], vertex) * boneWeights[i].weight2 +
  243. math.transform(boneTransforms[bone3], vertex) * boneWeights[i].weight3;
  244. var tangent = new float4(tangents[i].xyz, 0.0f);
  245. tangent =
  246. math.mul(boneTransforms[bone0], tangent) * boneWeights[i].weight0 +
  247. math.mul(boneTransforms[bone1], tangent) * boneWeights[i].weight1 +
  248. math.mul(boneTransforms[bone2], tangent) * boneWeights[i].weight2 +
  249. math.mul(boneTransforms[bone3], tangent) * boneWeights[i].weight3;
  250. deformedTangents[i] = new float4(math.normalize(tangent.xyz), tangents[i].w);
  251. }
  252. }
  253. internal unsafe static void Deform(Sprite sprite, Matrix4x4 invRoot, Transform[] boneTransformsArray, NativeArray<byte> deformVertexData)
  254. {
  255. Debug.Assert(sprite != null);
  256. Debug.Assert(sprite.GetVertexCount() == (deformVertexData.Length / sprite.GetVertexStreamSize()));
  257. var vertices = sprite.GetVertexAttribute<Vector3>(UnityEngine.Rendering.VertexAttribute.Position);
  258. var tangents = sprite.GetVertexAttribute<Vector4>(UnityEngine.Rendering.VertexAttribute.Tangent);
  259. var boneWeights = sprite.GetVertexAttribute<BoneWeight>(UnityEngine.Rendering.VertexAttribute.BlendWeight);
  260. var bindPoses = sprite.GetBindPoses();
  261. Debug.Assert(bindPoses.Length == boneTransformsArray.Length);
  262. Debug.Assert(boneWeights.Length == sprite.GetVertexCount());
  263. var boneTransforms = new NativeArray<Matrix4x4>(boneTransformsArray.Length, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
  264. for (var i = 0; i < boneTransformsArray.Length; ++i)
  265. boneTransforms[i] = boneTransformsArray[i].localToWorldMatrix;
  266. Deform(sprite, invRoot, vertices, tangents, boneWeights, boneTransforms, bindPoses, deformVertexData);
  267. boneTransforms.Dispose();
  268. }
  269. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  270. private static AtomicSafetyHandle CreateSafetyChecks<T>(ref NativeArray<T> array) where T : struct
  271. {
  272. var handle = AtomicSafetyHandle.Create();
  273. AtomicSafetyHandle.SetAllowSecondaryVersionWriting(handle, true);
  274. AtomicSafetyHandle.UseSecondaryVersion(ref handle);
  275. NativeArrayUnsafeUtility.SetAtomicSafetyHandle<T>(ref array, handle);
  276. return handle;
  277. }
  278. private static AtomicSafetyHandle CreateSafetyChecks<T>(ref NativeSlice<T> array) where T : struct
  279. {
  280. var handle = AtomicSafetyHandle.Create();
  281. AtomicSafetyHandle.SetAllowSecondaryVersionWriting(handle, true);
  282. AtomicSafetyHandle.UseSecondaryVersion(ref handle);
  283. NativeSliceUnsafeUtility.SetAtomicSafetyHandle<T>(ref array, handle);
  284. return handle;
  285. }
  286. private static void DisposeSafetyChecks(AtomicSafetyHandle handle)
  287. {
  288. AtomicSafetyHandle.Release(handle);
  289. }
  290. #endif
  291. internal static void Bake(this SpriteSkin spriteSkin, NativeArray<byte> deformVertexData)
  292. {
  293. if (!spriteSkin.isValid)
  294. throw new Exception("Bake error: invalid SpriteSkin");
  295. var sprite = spriteSkin.spriteRenderer.sprite;
  296. var boneTransformsArray = spriteSkin.boneTransforms;
  297. Deform(sprite, Matrix4x4.identity, boneTransformsArray, deformVertexData);
  298. }
  299. internal unsafe static void CalculateBounds(this SpriteSkin spriteSkin)
  300. {
  301. Debug.Assert(spriteSkin.isValid);
  302. var sprite = spriteSkin.sprite;
  303. var deformVertexData = new NativeArray<byte>(sprite.GetVertexStreamSize() * sprite.GetVertexCount(), Allocator.Temp, NativeArrayOptions.UninitializedMemory);
  304. void* dataPtr = NativeArrayUnsafeUtility.GetUnsafePtr(deformVertexData);
  305. var deformedPosSlice = NativeSliceUnsafeUtility.ConvertExistingDataToNativeSlice<Vector3>(dataPtr, sprite.GetVertexStreamSize(), sprite.GetVertexCount());
  306. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  307. NativeSliceUnsafeUtility.SetAtomicSafetyHandle(ref deformedPosSlice, NativeArrayUnsafeUtility.GetAtomicSafetyHandle(deformVertexData));
  308. #endif
  309. spriteSkin.Bake(deformVertexData);
  310. UpdateBounds(spriteSkin, deformVertexData);
  311. deformVertexData.Dispose();
  312. }
  313. internal static Bounds CalculateSpriteSkinBounds(NativeSlice<float3> deformablePositions)
  314. {
  315. float3 min = deformablePositions[0];
  316. float3 max = deformablePositions[0];
  317. for (int j = 1; j < deformablePositions.Length; ++j)
  318. {
  319. min = math.min(min, deformablePositions[j]);
  320. max = math.max(max, deformablePositions[j]);
  321. }
  322. float3 ext = (max - min) * 0.5F;
  323. float3 ctr = min + ext;
  324. Bounds bounds = new Bounds();
  325. bounds.center = ctr;
  326. bounds.extents = ext;
  327. return bounds;
  328. }
  329. internal static unsafe void UpdateBounds(this SpriteSkin spriteSkin, NativeArray<byte> deformedVertices)
  330. {
  331. byte* deformedPosOffset = (byte*)NativeArrayUnsafeUtility.GetUnsafePtr(deformedVertices);
  332. var spriteVertexCount = spriteSkin.sprite.GetVertexCount();
  333. var spriteVertexStreamSize = spriteSkin.sprite.GetVertexStreamSize();
  334. NativeSlice<float3> deformedPositions = NativeSliceUnsafeUtility.ConvertExistingDataToNativeSlice<float3>(deformedPosOffset, spriteVertexStreamSize, spriteVertexCount);
  335. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  336. var handle = CreateSafetyChecks<float3>(ref deformedPositions);
  337. #endif
  338. spriteSkin.bounds = CalculateSpriteSkinBounds(deformedPositions);
  339. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  340. DisposeSafetyChecks(handle);
  341. #endif
  342. InternalEngineBridge.SetLocalAABB(spriteSkin.spriteRenderer, spriteSkin.bounds);
  343. }
  344. }
  345. [BurstCompile]
  346. internal static class BurstedSpriteSkinUtilities
  347. {
  348. [BurstCompile]
  349. internal static bool ValidateBoneWeights(in NativeSlice<BoneWeight> boneWeights, int bindPoseCount)
  350. {
  351. var boneWeightCount = boneWeights.Length;
  352. for (var i = 0; i < boneWeightCount; ++i)
  353. {
  354. var boneWeight = boneWeights[i];
  355. var idx0 = boneWeight.boneIndex0;
  356. var idx1 = boneWeight.boneIndex1;
  357. var idx2 = boneWeight.boneIndex2;
  358. var idx3 = boneWeight.boneIndex3;
  359. if ((idx0 < 0 || idx0 >= bindPoseCount) ||
  360. (idx1 < 0 || idx1 >= bindPoseCount) ||
  361. (idx2 < 0 || idx2 >= bindPoseCount) ||
  362. (idx3 < 0 || idx3 >= bindPoseCount))
  363. return false;
  364. }
  365. return true;
  366. }
  367. }
  368. }