internal static void CreateBoneHierarchy(this SpriteSkin spriteSkin) { if (spriteSkin.spriteRenderer.sprite == null) { throw new InvalidOperationException("SpriteRenderer has no Sprite set"); } var spriteBones = spriteSkin.spriteRenderer.sprite.GetBones(); var transforms = new List <Transform>(); Transform root = null; //TODO: This code expects sprite bones to be in hierarchical order. Fix so it can generate from any order. foreach (var bone in spriteBones) { var parent = spriteSkin.transform; if (bone.parentId >= 0) { parent = transforms[bone.parentId].transform; } var newGameObject = CreateGameObject(bone.name, parent, bone.position, bone.rotation); transforms.Add(newGameObject.transform); if (bone.parentId < 0 && root == null) { root = newGameObject.transform; } } spriteSkin.rootBone = root; spriteSkin.boneTransforms = transforms.ToArray(); }
internal static void UpdateBounds(this SpriteSkin spriteSkin) { var worldToLocal = spriteSkin.transform.worldToLocalMatrix; var rootLocalToWorld = spriteSkin.rootBone.localToWorldMatrix; var unityBounds = spriteSkin.bounds; var matrix = math.mul(worldToLocal, rootLocalToWorld); var center = new float4(unityBounds.center, 1); var extents = new float4(unityBounds.extents, 0); var p0 = math.mul(matrix, center + new float4(-extents.x, -extents.y, extents.z, extents.w)); var p1 = math.mul(matrix, center + new float4(-extents.x, extents.y, extents.z, extents.w)); var p2 = math.mul(matrix, center + extents); var p3 = math.mul(matrix, center + new float4(extents.x, -extents.y, extents.z, extents.w)); var min = math.min(p0, math.min(p1, math.min(p2, p3))); var max = math.max(p0, math.max(p1, math.max(p2, p3))); extents = (max - min) * 0.5f; center = min + extents; var newBounds = new Bounds() { center = new Vector3(center.x, center.y, center.z), extents = new Vector3(extents.x, extents.y, extents.z) }; InternalEngineBridge.SetLocalAABB(spriteSkin.spriteRenderer, newBounds); }
internal static Vector3[] Bake(this SpriteSkin spriteSkin) { if (!spriteSkin.isValid) { throw new Exception("Bake error: invalid SpriteSkin"); } var sprite = spriteSkin.spriteRenderer.sprite; var boneTransforms = spriteSkin.boneTransforms; var bindPoses = sprite.GetBindPoses(); var boneWeights = sprite.GetBoneWeights(); var outputVertices = new NativeArray <Vector3>(sprite.GetVertexCount(), Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var transformMatrices = new NativeArray <Matrix4x4>(boneTransforms.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var vertices = sprite.GetVertexAttribute <Vector3>(VertexAttribute.Position); if (vertices.Length == 0 || transformMatrices.Length == 0 || boneWeights.Length == 0 || outputVertices.Length == 0) { return(new Vector3[0]); } for (int i = 0; i < boneTransforms.Length; ++i) { transformMatrices[i] = boneTransforms[i].localToWorldMatrix; } var jobHandle = SpriteSkinUtility.Deform(vertices, boneWeights, Matrix4x4.identity, bindPoses, transformMatrices, outputVertices); jobHandle.Complete(); var result = outputVertices.ToArray(); outputVertices.Dispose(); return(result); }
internal static SpriteSkinValidationResult Validate(this SpriteSkin spriteSkin) { var sprite = spriteSkin.spriteRenderer.sprite; if (sprite == null) { return(SpriteSkinValidationResult.SpriteNotFound); } var bindPoses = sprite.GetBindPoses(); if (bindPoses.Length == 0) { return(SpriteSkinValidationResult.SpriteHasNoSkinningInformation); } if (sprite.GetBoneWeights().Length == 0) { return(SpriteSkinValidationResult.SpriteHasNoWeights); } if (spriteSkin.rootBone == null) { return(SpriteSkinValidationResult.RootTransformNotFound); } if (spriteSkin.boneTransforms == null) { return(SpriteSkinValidationResult.InvalidTransformArray); } if (bindPoses.Length != spriteSkin.boneTransforms.Length) { return(SpriteSkinValidationResult.InvalidTransformArrayLength); } var rootFound = false; foreach (var boneTransform in spriteSkin.boneTransforms) { if (boneTransform == null) { return(SpriteSkinValidationResult.TransformArrayContainsNull); } if (boneTransform == spriteSkin.rootBone) { rootFound = true; } } if (!rootFound) { return(SpriteSkinValidationResult.RootNotFoundInTransformArray); } return(SpriteSkinValidationResult.Ready); }
internal static int CalculateTransformHash(this SpriteSkin spriteSkin) { int bits = 0; int boneTransformHash = GetHash(spriteSkin.transform.localToWorldMatrix) >> bits; bits++; foreach (var transform in spriteSkin.boneTransforms) { boneTransformHash ^= GetHash(transform.localToWorldMatrix) >> bits; bits = (bits + 1) % 8; } return(boneTransformHash); }
internal static Vector3[] Bake(this SpriteSkin spriteSkin) { if (!spriteSkin.isValid) { throw new Exception("Bake error: invalid SpriteSkin"); } var sprite = spriteSkin.spriteRenderer.sprite; var boneTransformsArray = spriteSkin.boneTransforms; var deformableVertices = new NativeArray <Vector3>(sprite.GetVertexCount(), Allocator.Temp, NativeArrayOptions.UninitializedMemory); Deform(sprite, Matrix4x4.identity, boneTransformsArray, ref deformableVertices); var result = deformableVertices.ToArray(); deformableVertices.Dispose(); return(result); }
internal static void CalculateBounds(this SpriteSkin spriteSkin) { Debug.Assert(spriteSkin.isValid); var rootBone = spriteSkin.rootBone; var deformableVertices = spriteSkin.Bake(); var bounds = new Bounds(); if (deformableVertices.Length > 0) { bounds.min = rootBone.InverseTransformPoint(deformableVertices[0]); bounds.max = bounds.min; } foreach (var v in deformableVertices) { bounds.Encapsulate(rootBone.InverseTransformPoint(v)); } bounds.extents = Vector3.Scale(bounds.extents, new Vector3(1.25f, 1.25f, 1f)); spriteSkin.bounds = bounds; }
internal static void CreateBoneHierarchy(this SpriteSkin spriteSkin) { if (spriteSkin.spriteRenderer.sprite == null) { throw new InvalidOperationException("SpriteRenderer has no Sprite set"); } var spriteBones = spriteSkin.spriteRenderer.sprite.GetBones(); var transforms = new Transform[spriteBones.Length]; Transform root = null; for (int i = 0; i < spriteBones.Length; ++i) { CreateGameObject(i, spriteBones, transforms, spriteSkin.transform); if (spriteBones[i].parentId < 0 && root == null) { root = transforms[i]; } } spriteSkin.rootBone = root; spriteSkin.boneTransforms = transforms; }
internal static void ResetBindPose(this SpriteSkin spriteSkin) { if (!spriteSkin.isValid) { throw new InvalidOperationException("SpriteSkin is not valid"); } var spriteBones = spriteSkin.spriteRenderer.sprite.GetBones(); var boneTransforms = spriteSkin.boneTransforms; for (int i = 0; i < boneTransforms.Length; ++i) { var boneTransform = boneTransforms[i]; var spriteBone = spriteBones[i]; if (spriteBone.parentId != -1) { boneTransform.localPosition = spriteBone.position; boneTransform.localRotation = spriteBone.rotation; boneTransform.localScale = Vector3.one; } } }
//TODO: Add other ways to find the transforms in case the named path fails internal static void Rebind(this SpriteSkin spriteSkin) { if (spriteSkin.spriteRenderer.sprite == null) { throw new ArgumentException("SpriteRenderer has no Sprite set"); } if (spriteSkin.rootBone == null) { throw new ArgumentException("SpriteSkin has no rootBone"); } var spriteBones = spriteSkin.spriteRenderer.sprite.GetBones(); var boneTransforms = new List <Transform>(); for (int i = 0; i < spriteBones.Length; ++i) { var boneTransformPath = CalculateBoneTransformPath(i, spriteBones); var boneTransform = spriteSkin.rootBone.Find(boneTransformPath); boneTransforms.Add(boneTransform); } spriteSkin.boneTransforms = boneTransforms.ToArray(); }