private IEnumerator BakeAnimationTexture(string path)
                    {
                        _working = true;

                        GameObject gameObject = Instantiate(_evaluatedObject);

                        {
                            if (PrefabUtility.IsAnyPrefabInstanceRoot(gameObject))
                            {
                                PrefabUtility.UnpackPrefabInstance(gameObject, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);
                            }

                            gameObject.SetActive(true);
                            gameObject.transform.parent        = null;
                            gameObject.transform.localPosition = Vector3.zero;
                            gameObject.transform.localRotation = Quaternion.identity;
                            gameObject.transform.localScale    = Vector3.one;
                        }

                        AnimationClip[] animationClips       = _animations;
                        string[]        animationStateNames  = null;
                        int[]           animationStateLayers = null;
                        Animator        animator             = null;

                        //If using animator then get clips and state names from controller
                        if (_useAnimator)
                        {
                            animator = GameObjectUtils.GetComponent <Animator>(gameObject, true);
                            GetAnimationClipsFromAnimator(animator, out animationClips, out animationStateNames, out animationStateLayers);

                            if (animationClips.Length == 0)
                            {
                                DestroyImmediate(gameObject);
                                _working = false;
                                yield break;
                            }

                            AnimatorUtility.DeoptimizeTransformHierarchy(animator.gameObject);
                            animator.cullingMode = AnimatorCullingMode.AlwaysAnimate;
                        }

                        Matrix4x4 rootMat = gameObject.transform.worldToLocalMatrix;

                        SkinnedMeshRenderer[] skinnedMeshes = gameObject.GetComponentsInChildren <SkinnedMeshRenderer>();
                        Transform[]           bones         = skinnedMeshes[_skinnedMeshIndex].bones;
                        Matrix4x4[]           bindposes     = skinnedMeshes[_skinnedMeshIndex].sharedMesh.bindposes;
                        int numBones = bones.Length;

                        if (numBones == 0)
                        {
                            DestroyImmediate(gameObject);
                            _working = false;
                            yield break;
                        }

                        Vector3[]    origBonePositons  = new Vector3[numBones];
                        Quaternion[] origBoneRotations = new Quaternion[numBones];
                        Vector3[]    origBoneScales    = new Vector3[numBones];

                        GPUAnimations.Animation[] animations = new GPUAnimations.Animation[animationClips.Length];

                        //3d array - animation / frame / bones
                        Matrix4x4[][][] boneMatricies = new Matrix4x4[animations.Length + 1][][];

                        //Insert dummy one frame animation at start which is just the reference pose
                        boneMatricies[0]    = new Matrix4x4[1][];
                        boneMatricies[0][0] = new Matrix4x4[numBones];

                        for (int i = 0; i < numBones; i++)
                        {
                            origBonePositons[i]  = bones[i].localPosition;
                            origBoneRotations[i] = bones[i].localRotation;
                            origBoneScales[i]    = bones[i].localScale;

                            //Save reference pose bone matrix
                            boneMatricies[0][0][i] = rootMat * bones[i].localToWorldMatrix * bindposes[i];
                        }

                        //Start after first frame (as this frame is our reference pose)
                        int startOffset          = 1;
                        int totalNumberOfSamples = 1;

                        for (int animIndex = 0; animIndex < animations.Length; animIndex++)
                        {
                            AnimationClip clip          = animationClips[animIndex];
                            bool          hasRootMotion = _useAnimator && clip.hasMotionCurves;

                            string name         = clip.name;
                            int    totalFrames  = Mathf.Max(Mathf.FloorToInt(clip.length * clip.frameRate), 1);
                            int    totalSamples = totalFrames + 1;
                            totalNumberOfSamples += totalSamples;

                            WrapMode         wrapMode = GetClipWrapMode(clip);
                            AnimationEvent[] events   = clip.events;

                            //Sample animation
                            boneMatricies[animIndex + 1] = new Matrix4x4[totalSamples][];

                            Vector3[] rootMotionVelocities        = null;
                            Vector3[] rootMotionAngularVelocities = null;

                            if (hasRootMotion)
                            {
                                rootMotionVelocities        = new Vector3[totalSamples];
                                rootMotionAngularVelocities = new Vector3[totalSamples];
                            }

                            //Reset all bone transforms before sampling animations
                            for (int i = 0; i < numBones; i++)
                            {
                                bones[i].localPosition = origBonePositons[i];
                                bones[i].localRotation = origBoneRotations[i];
                                bones[i].localScale    = origBoneScales[i];
                            }

                            //If using an animator, start playing animation with correct layer weights set
                            if (_useAnimator)
                            {
                                for (int layer = 1; layer < animator.layerCount; layer++)
                                {
                                    animator.SetLayerWeight(animIndex, layer == animationStateLayers[animIndex] ? 1.0f : 0.0f);
                                }

                                animator.Play(animationStateNames[animIndex], animationStateLayers[animIndex]);

                                //Needed to prevent first frame pop?
                                {
                                    animator.Update(0f);
                                    yield return(null);

                                    animator.Play(animationStateNames[animIndex], animationStateLayers[animIndex]);
                                    animator.Update(0f);
                                    yield return(null);

                                    animator.Play(animationStateNames[animIndex], animationStateLayers[animIndex]);
                                    animator.Update(0f);
                                    yield return(null);
                                }
                            }

                            for (int i = 0; i < totalSamples; i++)
                            {
                                float normalisedTime = i / (float)totalFrames;

                                //Using animator, update animator to progress forward with animation
                                if (_useAnimator)
                                {
                                    for (int layer = 1; layer < animator.layerCount; layer++)
                                    {
                                        animator.SetLayerWeight(layer, 0.0f);
                                    }

                                    animator.SetLayerWeight(animationStateLayers[animIndex], 1.0f);
                                    float layerWeight = animator.GetLayerWeight(animationStateLayers[animIndex]);

                                    animator.Play(animationStateNames[animIndex], animationStateLayers[animIndex], normalisedTime);
                                    animator.Update(0f);

                                    layerWeight = animator.GetLayerWeight(animationStateLayers[animIndex]);

                                    //Wait for end of frame
                                    yield return(null);
                                }
                                //Sample animation using legacy system
                                else
                                {
                                    bool wasLegacy = clip.legacy;
                                    clip.legacy = true;
                                    clip.SampleAnimation(gameObject, normalisedTime * clip.length);
                                    clip.legacy = wasLegacy;
                                }

                                //Save bone matrices
                                boneMatricies[animIndex + 1][i] = new Matrix4x4[numBones];

                                for (int boneIndex = 0; boneIndex < numBones; boneIndex++)
                                {
                                    boneMatricies[animIndex + 1][i][boneIndex] = rootMat * bones[boneIndex].localToWorldMatrix * bindposes[boneIndex];
                                }

                                //Save root motion velocities
                                if (hasRootMotion)
                                {
                                    rootMotionVelocities[i]        = animator.velocity;
                                    rootMotionAngularVelocities[i] = animator.angularVelocity;
                                }
                            }

                            //Create animation
                            animations[animIndex] = new GPUAnimations.Animation(name, startOffset, totalFrames, clip.frameRate, wrapMode, events, hasRootMotion, rootMotionVelocities, rootMotionAngularVelocities);
                            startOffset          += totalSamples;
                        }

                        //Create and save texture
                        Texture2D texture;

                        {
                            if (!CalculateTextureSize(totalNumberOfSamples, numBones, out int textureSize))
                            {
                                DestroyImmediate(gameObject);
                                _working = false;
                                yield break;
                            }

                            texture = new Texture2D(textureSize, textureSize, TextureFormat.RGBAHalf, false)
                            {
                                filterMode = FilterMode.Point
                            };

                            //Loop through animations / frames / bones setting pixels for each bone matrix
                            int pixelx = 0;
                            int pixely = 0;

                            //Foreach animation
                            for (int animIndex = 0; animIndex < boneMatricies.Length; animIndex++)
                            {
                                //For each frame
                                for (int j = 0; j < boneMatricies[animIndex].Length; j++)
                                {
                                    //Convert all frame bone matrices to colors
                                    Color[] matrixPixels = ConvertMatricesToColor(boneMatricies[animIndex][j]);
                                    texture.SetPixels(pixelx, pixely, GPUAnimations.kPixelsPerBoneMatrix, numBones, matrixPixels);

                                    //Shift to next frame position
                                    pixelx += GPUAnimations.kPixelsPerBoneMatrix;

                                    //If less than 4 pixels from edge, move to next row
                                    if (textureSize - pixelx < GPUAnimations.kPixelsPerBoneMatrix)
                                    {
                                        pixelx  = 0;
                                        pixely += numBones;
                                    }
                                }
                            }

                            texture.Apply();
                        }

                        //Save our exposed bones
                        GPUAnimations.ExposedBone[] exposedBones;
                        {
                            exposedBones = new GPUAnimations.ExposedBone[_exposedBones.Count];

                            for (int i = 0; i < exposedBones.Length; i++)
                            {
                                //Work out bone index
                                int boneIndex = _exposedBones[i];

                                Matrix4x4 inverseBindPose = bindposes[boneIndex].inverse;

                                //Work out bone matrixes
                                Vector3[]    exposedBonePositions = new Vector3[totalNumberOfSamples];
                                Quaternion[] exposedBoneRotations = new Quaternion[totalNumberOfSamples];
                                Vector3[]    exposedBoneScales    = new Vector3[totalNumberOfSamples];

                                int sampleIndex = 0;
                                for (int anim = 0; anim < boneMatricies.Length; anim++)
                                {
                                    for (int frame = 0; frame < boneMatricies[anim].Length; frame++)
                                    {
                                        Matrix4x4 boneMatrix = boneMatricies[anim][frame][boneIndex] * inverseBindPose;

                                        exposedBonePositions[sampleIndex] = boneMatrix.MultiplyPoint3x4(Vector3.zero);
                                        exposedBoneRotations[sampleIndex] = boneMatrix.rotation;
                                        exposedBoneScales[sampleIndex]    = boneMatrix.lossyScale;

                                        sampleIndex++;
                                    }
                                }

                                exposedBones[i] = new GPUAnimations.ExposedBone(boneIndex, exposedBonePositions, exposedBoneRotations, exposedBoneScales);
                            }
                        }

                        GPUAnimations animationTexture = new GPUAnimations(texture, animations, _boneNames, exposedBones);

                        SaveAnimationTexture(animationTexture, path);

                        DestroyImmediate(gameObject);
                        _working = false;
                        yield break;
                    }
Exemplo n.º 2
0
                public static GPUAnimations Read(BinaryReader reader)
                {
                    string[] bones = new string[reader.ReadInt32()];
                    for (int i = 0; i < bones.Length; i++)
                    {
                        bones[i] = reader.ReadString();
                    }

                    int animCount = reader.ReadInt32();

                    GPUAnimations.Animation[] animations = new GPUAnimations.Animation[animCount];

                    for (int i = 0; i < animCount; i++)
                    {
                        string   name        = reader.ReadString();
                        int      startOffset = reader.ReadInt32();
                        int      totalFrames = reader.ReadInt32();
                        float    fps         = reader.ReadSingle();
                        WrapMode wrapMode    = (WrapMode)reader.ReadInt32();

                        int numEvents           = reader.ReadInt32();
                        AnimationEvent[] events = new AnimationEvent[numEvents];

                        for (int j = 0; j < numEvents; j++)
                        {
                            events[j] = new AnimationEvent
                            {
                                time         = reader.ReadSingle(),
                                functionName = reader.ReadString(),

                                stringParameter = reader.ReadString(),
                                floatParameter  = reader.ReadSingle(),
                                intParameter    = reader.ReadInt32()
                                                  //TO DO?
                                                  //evnt.objectReferenceParameter = reader.Rea();
                            };
                        }

                        bool hasRootMotion = reader.ReadBoolean();

                        Vector3[] rootMotionVelocities        = null;
                        Vector3[] rootMotionAngularVelocities = null;

                        if (hasRootMotion)
                        {
                            rootMotionVelocities        = new Vector3[totalFrames];
                            rootMotionAngularVelocities = new Vector3[totalFrames];

                            for (int j = 0; j < totalFrames; j++)
                            {
                                rootMotionVelocities[j]        = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                                rootMotionAngularVelocities[j] = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                            }
                        }

                        animations[i] = new GPUAnimations.Animation(name, startOffset, totalFrames, fps, wrapMode, events, hasRootMotion, rootMotionVelocities, rootMotionAngularVelocities);
                    }

                    int exposedBoneCount = reader.ReadInt32();

                    GPUAnimations.ExposedBone[] exposedBones = new GPUAnimations.ExposedBone[exposedBoneCount];

                    for (int i = 0; i < exposedBoneCount; i++)
                    {
                        int          boneIndex     = reader.ReadInt32();
                        int          numSamples    = reader.ReadInt32();
                        Vector3[]    bonePositions = new Vector3[numSamples];
                        Quaternion[] boneRotations = new Quaternion[numSamples];
                        Vector3[]    boneScales    = new Vector3[numSamples];

                        for (int j = 0; j < numSamples; j++)
                        {
                            bonePositions[j] = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                            boneRotations[j] = new Quaternion(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                            boneScales[j]    = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                        }

                        exposedBones[i] = new GPUAnimations.ExposedBone(boneIndex, bonePositions, boneRotations, boneScales);
                    }


                    TextureFormat format        = (TextureFormat)reader.ReadInt32();
                    int           textureWidth  = reader.ReadInt32();
                    int           textureHeight = reader.ReadInt32();
                    int           byteLength    = reader.ReadInt32();

                    byte[] bytes = new byte[byteLength];
                    bytes = reader.ReadBytes(byteLength);
                    Texture2D texture = new Texture2D(textureWidth, textureHeight, format, false);

                    texture.filterMode = FilterMode.Point;
                    texture.LoadRawTextureData(bytes);
                    texture.Apply();

                    return(new GPUAnimations(texture, animations, bones, exposedBones));
                }