Example #1
0
        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();
        }