Example #1
0
                public override void Initialise(GPUAnimatorRenderer renderer)
                {
                    base.Initialise(renderer);

                    _skinnedMeshRenderer     = GameObjectUtils.GetComponent <SkinnedMeshRenderer>(this.gameObject, true);
                    _animationStates         = new GPUAnimationState[0];
                    _primaryAnimationState   = null;
                    _secondaryAnimationState = null;

                    GPUAnimations animations = _renderer._animations.GetAnimations();

                    _animationStates = new GPUAnimationState[animations._animations.Length];

                    for (int i = 0; i < animations._animations.Length; i++)
                    {
                        _animationStates[i] = new GPUAnimationState(this, animations._animations[i]);
                    }

                    _activeAnimationStates = new List <GPUAnimationState>(animations._animations.Length + 1);

                    _primaryAnimationState   = GetAnimationState(_defaultAnimation);
                    _secondaryAnimationState = null;

                    if (_primaryAnimationState != null && _playAutomatically)
                    {
                        _primaryAnimationState.Enabled = true;
                        _primaryAnimationState.Weight  = 1.0f;

                        if (_wrapMode != WrapMode.Default)
                        {
                            _primaryAnimationState.WrapMode = _wrapMode;
                        }
                    }
                }
Example #2
0
                private static int GetExposedBoneIndex(GPUAnimations animations, string boneName)
                {
                    if (animations != null)
                    {
                        string[] boneNames = animations._bones;

                        for (int i = 0; i < boneNames.Length; i++)
                        {
                            if (boneNames[i] == boneName)
                            {
                                for (int j = 0; j < animations._exposedBones.Length; j++)
                                {
                                    if (animations._exposedBones[j]._boneIndex == i)
                                    {
                                        return(j);
                                    }
                                }

                                UnityEngine.Debug.LogError("Bone '" + boneName + "' isn't exposed in GPU Animations Asset");
                                return(-1);
                            }
                        }
                    }

                    return(-1);
                }
 private void LoadIfNeeded()
 {
     if (_animationTexture == null && _asset != null)
     {
         _animationTexture = GPUAnimations.LoadFromFile(_asset);
     }
 }
                private GPUAnimations.Animation GetAnimation(int index)
                {
                    GPUAnimations animations = _animationTexture.GetAnimations();

                    GPUAnimations.Animation animation = animations._animations[Mathf.Clamp(index, 0, animations._animations.Length)];
                    return(animation);
                }
                    private void OnDrawAnimationItem(Rect rect, int index, bool selected, bool focused)
                    {
                        GPUAnimatorParticleSystem particleSystem = target as GPUAnimatorParticleSystem;

                        GPUAnimatorParticleSystem.ParticleAnimation animation = (GPUAnimatorParticleSystem.ParticleAnimation)_animationList.list[index];

                        float columnWidth = rect.width / 3f;

                        rect.width = columnWidth;

                        GPUAnimations animations = particleSystem._animationTexture.GetAnimations();

                        GUIContent[] animNames = new GUIContent[animations._animations.Length];
                        for (int i = 0; i < animNames.Length; i++)
                        {
                            animNames[i] = new GUIContent(animations._animations[i]._name);
                        }

                        animation._animationIndex = EditorGUI.Popup(rect, animation._animationIndex, animNames);

                        rect.x += columnWidth;
                        animation._probability = EditorGUI.Slider(rect, animation._probability, 0f, 1f);

                        rect.x += columnWidth;
                        {
                            rect.width = columnWidth * 0.5f;
                            animation._speedRange._min = EditorGUI.FloatField(rect, animation._speedRange._min);
                            rect.x += rect.width;
                            animation._speedRange._max = EditorGUI.FloatField(rect, animation._speedRange._max);
                        }

                        _animationList.list[index] = animation;
                    }
Example #6
0
                private void UpdateBoneTransform()
                {
                    bool followPosition = (_flags & TransformFlags.Translate) != 0;
                    bool followRotation = (_flags & TransformFlags.Rotate) != 0;
                    bool followScale    = (_flags & TransformFlags.Scale) != 0;

                    Vector3    localPosition;
                    Quaternion localRotation;
                    Vector3    localScale;

                    //Work out local space bone transform
                    {
                        GPUAnimations animations = _animator.GetRenderer()._animations.GetAnimations();

                        float curAnimWeight = _animator.GetMainAnimationWeight();
                        GetFrameInfo(_animator.GetMainAnimationFrame(), out int prevFrame, out int nextFrame, out float frameLerp);
                        animations._exposedBones[_exposedBoneIndex].GetBoneTransform(prevFrame, nextFrame, frameLerp, followPosition, followRotation, followScale, out localPosition, out localRotation, out localScale);

                        if (curAnimWeight < 1.0f)
                        {
                            GetFrameInfo(_animator.GetBackgroundAnimationFrame(), out prevFrame, out nextFrame, out frameLerp);
                            animations._exposedBones[_exposedBoneIndex].GetBoneTransform(prevFrame, nextFrame, frameLerp, followPosition, followRotation, followScale, out Vector3 backgroundLocalPosition, out Quaternion backgroundLocalRotation, out Vector3 backgroundLocalScale);

                            if (followPosition)
                            {
                                localPosition = Vector3.Lerp(backgroundLocalPosition, localPosition, curAnimWeight);
                            }
                            if (followRotation)
                            {
                                localRotation = Quaternion.Slerp(backgroundLocalRotation, localRotation, curAnimWeight);
                            }
                            if (followScale)
                            {
                                localScale = Vector3.Lerp(backgroundLocalScale, localScale, curAnimWeight);
                            }
                        }
                    }

                    //Set world transform from this
                    {
                        if (followPosition && followRotation)
                        {
                            this.transform.SetPositionAndRotation(_animator.transform.TransformPoint(localPosition), _animator.transform.rotation * localRotation);
                        }
                        else if (followPosition)
                        {
                            this.transform.position = _animator.transform.TransformPoint(localPosition);
                        }
                        else if (followRotation)
                        {
                            this.transform.rotation = _animator.transform.rotation * localRotation;
                        }

                        if (followScale)
                        {
                            GameObjectUtils.SetTransformWorldScale(this.transform, Vector3.Scale(_animator.transform.lossyScale, localScale));
                        }
                    }
                }
Example #7
0
 private void LoadIfNeeded()
 {
     if (_animationTexture == null && _asset != null)
     {
         BinaryReader reader = new BinaryReader(new MemoryStream(_asset.bytes));
         _animationTexture = GPUAnimationsIO.Read(reader);
     }
 }
                public void SetNormalizedTime(float normalizedTime)
                {
                    if (_gameObject != null)
                    {
                        //TO DO! use wrap mode to clamp, loop or ping-pong


                        float prevFrame = _frame;
                        _frame = (_animation._totalFrames - 1) * (normalizedTime - Mathf.Floor(normalizedTime));

                        GPUAnimations.CheckForEvents(_gameObject, _animation, prevFrame, _frame);
                    }
                }
Example #9
0
                private void Initialise()
                {
                    _initialised = true;

                    GPUAnimations animations = _animator.GetRenderer()._animations.GetAnimations();

                    _exposedBoneIndex      = GetExposedBoneIndex(animations, _boneName);
                    _exposedBoneNumSamples = animations._exposedBones[_exposedBoneIndex]._cachedBonePositions.Length;

                    if (_exposedBoneIndex == -1)
                    {
                        this.enabled = false;
                    }
                }
Example #10
0
                public GPUAnimatorOverrideController(RuntimeAnimatorController controller, GPUAnimations animations, List <KeyValuePair <AnimationClip, AnimationClip> > overrideClips) : base(controller)
                {
                    this.name = controller.name + " (GPU Animated)";

                    _animations      = animations;
                    _animationLookUp = new Dictionary <AnimationClip, int>();

                    foreach (KeyValuePair <AnimationClip, AnimationClip> clipPair in overrideClips)
                    {
                        _animationLookUp[clipPair.Value] = GetAnimationIndex(clipPair.Key);
                    }

                    ApplyOverrides(overrideClips);
                }
Example #11
0
                public GPUAnimatorOverrideController(RuntimeAnimatorController controller, GPUAnimations animations) : base(controller)
                {
                    this.name = controller.name + " (GPU Animated)";

                    _animations      = animations;
                    _animationLookUp = new Dictionary <AnimationClip, int>();

                    List <KeyValuePair <AnimationClip, AnimationClip> > overrideClips = new List <KeyValuePair <AnimationClip, AnimationClip> >();

                    foreach (AnimationClip origClip in controller.animationClips)
                    {
                        //Override original animation
                        AnimationClip overrideClip = CreateOverrideClip(origClip);
                        overrideClips.Add(new KeyValuePair <AnimationClip, AnimationClip>(origClip, overrideClip));
                        //Cache what gpu animation it corresponds too
                        _animationLookUp[overrideClip] = GetAnimationIndex(origClip);
                    }

                    ApplyOverrides(overrideClips);
                }
                    private static void SaveAnimationTexture(GPUAnimations animationTexture, string fileName)
                    {
                        string directory = Path.GetDirectoryName(fileName);

                        if (!Directory.Exists(directory))
                        {
                            Directory.CreateDirectory(directory);
                        }

                        FileStream   file   = File.Open(fileName, FileMode.Create);
                        BinaryWriter writer = new BinaryWriter(file);

                        GPUAnimationsIO.Write(animationTexture, writer);

                        file.Close();

#if UNITY_EDITOR
                        //Refresh the saved asset
                        AssetUtils.RefreshAsset(fileName);
#endif
                    }
                public void Update(float deltaTime)
                {
                    if (_gameObject != null && deltaTime > 0f && _speed > 0f)
                    {
                        float prevFrame = _frame;

                        _frame += deltaTime * _animation._fps * _speed;

                        GPUAnimations.CheckForEvents(_gameObject, _animation, prevFrame, _frame);

                        if (_frame > _animation._totalFrames - 1)
                        {
                            switch (_wrapMode)
                            {
                            case WrapMode.Clamp:
                            case WrapMode.ClampForever:
                            {
                                _frame = _animation._totalFrames - 1;
                            }
                            break;

                            case WrapMode.PingPong:
                            {
                                //TO DO! speed should reverese
                            }
                            break;

                            case WrapMode.Loop:
                            case WrapMode.Default:
                            default:
                            {
                                _frame -= (_animation._totalFrames - 1);
                            }
                            break;
                            }
                        }
                    }
                }
                    private static void SaveAnimationTexture(GPUAnimations animationTexture, string fileName)
                    {
                        string directory = Path.GetDirectoryName(fileName);

                        if (!Directory.Exists(directory))
                        {
                            Directory.CreateDirectory(directory);
                        }

                        FileStream   file   = File.Open(fileName, FileMode.Create);
                        BinaryWriter writer = new BinaryWriter(file);

                        writer.Write(animationTexture._numBones);
                        writer.Write(animationTexture._animations.Length);

                        for (int i = 0; i < animationTexture._animations.Length; i++)
                        {
                            writer.Write(animationTexture._animations[i]._name);
                            writer.Write(animationTexture._animations[i]._startFrameOffset);
                            writer.Write(animationTexture._animations[i]._totalFrames);
                            writer.Write(animationTexture._animations[i]._fps);
                            writer.Write((int)animationTexture._animations[i]._wrapMode);

                            writer.Write(animationTexture._animations[i]._events.Length);

                            for (int j = 0; j < animationTexture._animations[i]._events.Length; j++)
                            {
                                writer.Write(animationTexture._animations[i]._events[j].time);
                                writer.Write(animationTexture._animations[i]._events[j].functionName);
                                writer.Write(animationTexture._animations[i]._events[j].stringParameter);
                                writer.Write(animationTexture._animations[i]._events[j].floatParameter);
                                writer.Write(animationTexture._animations[i]._events[j].intParameter);
                                //TO DO?
                                //writer.Write(animationTexture._animations[i]._events[j].objectReferenceParameter);
                            }

                            writer.Write(animationTexture._animations[i]._hasRootMotion);

                            if (animationTexture._animations[i]._hasRootMotion)
                            {
                                for (int j = 0; j < animationTexture._animations[i]._totalFrames; j++)
                                {
                                    writer.Write(animationTexture._animations[i]._rootMotionVelocities[j].x);
                                    writer.Write(animationTexture._animations[i]._rootMotionVelocities[j].y);
                                    writer.Write(animationTexture._animations[i]._rootMotionVelocities[j].z);

                                    writer.Write(animationTexture._animations[i]._rootMotionAngularVelocities[j].x);
                                    writer.Write(animationTexture._animations[i]._rootMotionAngularVelocities[j].y);
                                    writer.Write(animationTexture._animations[i]._rootMotionAngularVelocities[j].z);
                                }
                            }
                        }

                        //Write texture!
                        byte[] bytes = animationTexture._texture.GetRawTextureData();
                        writer.Write(animationTexture._texture.width);
                        writer.Write(animationTexture._texture.height);
                        writer.Write(bytes.Length);
                        writer.Write(bytes);

                        file.Close();

#if UNITY_EDITOR
                        //Refresh the saved asset
                        AssetUtils.RefreshAsset(fileName);
#endif
                    }
                    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;
                    }
                public static void Write(GPUAnimations animations, BinaryWriter writer)
                {
                    writer.Write(animations._bones.Length);
                    for (int i = 0; i < animations._bones.Length; i++)
                    {
                        writer.Write(animations._bones[i]);
                    }

                    writer.Write(animations._animations.Length);

                    for (int i = 0; i < animations._animations.Length; i++)
                    {
                        writer.Write(animations._animations[i]._name);
                        writer.Write(animations._animations[i]._startFrameOffset);
                        writer.Write(animations._animations[i]._totalFrames);
                        writer.Write(animations._animations[i]._fps);
                        writer.Write((int)animations._animations[i]._wrapMode);

                        writer.Write(animations._animations[i]._events.Length);

                        for (int j = 0; j < animations._animations[i]._events.Length; j++)
                        {
                            writer.Write(animations._animations[i]._events[j].time);
                            writer.Write(animations._animations[i]._events[j].functionName);
                            writer.Write(animations._animations[i]._events[j].stringParameter);
                            writer.Write(animations._animations[i]._events[j].floatParameter);
                            writer.Write(animations._animations[i]._events[j].intParameter);
                            //TO DO?
                            //writer.Write(animationTexture._animations[i]._events[j].objectReferenceParameter);
                        }

                        writer.Write(animations._animations[i]._hasRootMotion);

                        if (animations._animations[i]._hasRootMotion)
                        {
                            for (int j = 0; j < animations._animations[i]._totalFrames; j++)
                            {
                                writer.Write(animations._animations[i]._rootMotionVelocities[j].x);
                                writer.Write(animations._animations[i]._rootMotionVelocities[j].y);
                                writer.Write(animations._animations[i]._rootMotionVelocities[j].z);

                                writer.Write(animations._animations[i]._rootMotionAngularVelocities[j].x);
                                writer.Write(animations._animations[i]._rootMotionAngularVelocities[j].y);
                                writer.Write(animations._animations[i]._rootMotionAngularVelocities[j].z);
                            }
                        }
                    }

                    writer.Write(animations._exposedBones.Length);

                    for (int i = 0; i < animations._exposedBones.Length; i++)
                    {
                        writer.Write(animations._exposedBones[i]._boneIndex);

                        writer.Write(animations._exposedBones[i]._cachedBonePositions.Length);

                        for (int j = 0; j < animations._exposedBones[i]._cachedBonePositions.Length; j++)
                        {
                            writer.Write(animations._exposedBones[i]._cachedBonePositions[j].x);
                            writer.Write(animations._exposedBones[i]._cachedBonePositions[j].y);
                            writer.Write(animations._exposedBones[i]._cachedBonePositions[j].z);

                            writer.Write(animations._exposedBones[i]._cachedBoneRotations[j].x);
                            writer.Write(animations._exposedBones[i]._cachedBoneRotations[j].y);
                            writer.Write(animations._exposedBones[i]._cachedBoneRotations[j].z);
                            writer.Write(animations._exposedBones[i]._cachedBoneRotations[j].w);

                            writer.Write(animations._exposedBones[i]._cachedBoneScales[j].x);
                            writer.Write(animations._exposedBones[i]._cachedBoneScales[j].y);
                            writer.Write(animations._exposedBones[i]._cachedBoneScales[j].z);
                        }
                    }


                    byte[] bytes = animations._texture.GetRawTextureData();

                    writer.Write((int)animations._texture.format);
                    writer.Write(animations._texture.width);
                    writer.Write(animations._texture.height);
                    writer.Write(bytes.Length);
                    writer.Write(bytes);
                }
                    private IEnumerator BakeAnimationTexture()
                    {
                        GameObject gameObject = Instantiate(_animatorObject);

                        SkinnedMeshRenderer[] skinnedMeshes = gameObject.GetComponentsInChildren <SkinnedMeshRenderer>();
                        SkinnedMeshRenderer   skinnedMesh   = skinnedMeshes[_skinnedMeshIndex];

                        Transform[]     bones          = skinnedMesh.bones;
                        Matrix4x4[]     bindposes      = skinnedMesh.sharedMesh.bindposes;
                        AnimationClip[] animationClips = _animations;
                        Animator        animator       = null;

                        string[] animationStateNames = null;

                        if (skinnedMesh.bones.Length == 0)
                        {
                            yield break;
                        }

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

                            if (animator == null)
                            {
                                yield break;
                            }

                            GetAnimationClipsFromAnimator(animator, out animationClips, out animationStateNames);

                            if (animationClips.Length == 0)
                            {
                                yield break;
                            }
                        }

                        int numBones = bones.Length;

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

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

                        Matrix4x4 rootMat     = gameObject.transform.worldToLocalMatrix;
                        int       startOffset = 0;

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

                            string           name        = clip.name;
                            int              totalFrames = Mathf.FloorToInt(clip.length * clip.frameRate);
                            WrapMode         wrapMode    = clip.wrapMode;
                            AnimationEvent[] events      = clip.events;

                            //Sample animation
                            boneWorldMatrix[animIndex] = new Matrix4x4[totalFrames][];

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

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

                            float lastFrame = totalFrames - 1;

                            for (int frame = 0; frame < totalFrames; frame++)
                            {
                                float normalisedTime = frame / lastFrame;

                                //Sample animation using legacy system
                                if (animator == null)
                                {
                                    bool wasLegacy = clip.legacy;
                                    clip.legacy = true;
                                    clip.SampleAnimation(gameObject, normalisedTime * clip.length);
                                    clip.legacy = wasLegacy;
                                }
                                //Using animator, update animator to progress forward with animation
                                else
                                {
                                    animator.Play(animationStateNames[animIndex], 0, normalisedTime);
                                    animator.Update(0f);
                                    yield return(null);
                                }

                                //Save bone matrices
                                boneWorldMatrix[animIndex][frame] = new Matrix4x4[numBones];

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

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

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

                        //Create and save texture! Work out width!
                        TextureFormat format = TextureFormat.RGBAHalf;
                        int           textureSize;

                        if (!CalculateTextureSize(boneWorldMatrix, out textureSize))
                        {
                            yield break;
                        }

                        Texture2D texture = new Texture2D(textureSize, textureSize, format, false);

                        texture.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 < boneWorldMatrix.Length; animIndex++)
                        {
                            //For each frame
                            for (int j = 0; j < boneWorldMatrix[animIndex].Length; j++)
                            {
                                //Convert all frame bone matrices to colors
                                Color[] matrixPixels = ConvertMatricesToColor(boneWorldMatrix[animIndex][j]);
                                texture.SetPixels(pixelx, pixely, 4, numBones, matrixPixels);

                                //Shift to next frame position
                                pixelx += 4;

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

                        texture.Apply();

                        GPUAnimations animationTexture = new GPUAnimations(animations, numBones, texture);

                        SaveAnimationTexture(animationTexture, _currentFileName);

                        DestroyImmediate(gameObject);
                    }
 public void UnloadTexture()
 {
     _animationTexture = null;
 }