예제 #1
0
        protected virtual bool DisplayFrame(int previousFrame)
        {
            if (currentFrame == previousFrame || currentAnimIndex < 0)
            {
                return(false);
            }
            if (hasExposedTransforms && exposedTransformCrossfade.isFading)
            {
                if (exposedTransformCrossfade.currentFrame >= exposedTransformCrossfade.framesNeeded)
                {
                    exposedTransformCrossfade.ReturnFrame(false);
                }
                else
                {
                    exposedTransformCrossfade.exposedTransformJobHandles[exposedTransformCrossfade.currentFrame].Complete();
                    if (exposedTransformCrossfade.outputMatrix != null)
                    {
                        var         exposedTransforms = currentAnimation.ExposedTransforms;
                        Matrix4x4[] positions         = AllocatedArray <Matrix4x4> .Get(exposedTransforms.Length);

                        exposedTransformCrossfade.outputMatrix[exposedTransformCrossfade.currentFrame].CopyTo(positions);
                        for (int i = 0; i < positions.Length; i++)
                        {
                            Transform child = null;
                            if (childMap.TryGetValue(exposedTransforms[i], out child))
                            {
                                MatrixUtils.FromMatrix4x4(child, positions[i]);
                            }
                        }
                    }
                    // apply root motion
                    var  fromFrame       = exposedTransformCrossfade.fromFrame;
                    var  toFrame         = exposedTransformCrossfade.toFrame;
                    bool applyRootMotion = currentAnimation.RootMotionMode == RootMotionMode.AppliedToTransform;
                    if (applyRootMotion)
                    {
                        float      delta = exposedTransformCrossfade.currentFrame / (float)exposedTransformCrossfade.framesNeeded;
                        Vector3    pos   = Vector3.Lerp(fromFrame.rootMotionPosition, toFrame.rootMotionPosition, delta);
                        Quaternion rot   = Quaternion.Lerp(fromFrame.rootMotionRotation, toFrame.rootMotionRotation, delta);
                        transform.Translate(pos, Space.Self);
                        transform.Rotate(rot.eulerAngles * Time.deltaTime, Space.Self);
                    }
                    exposedTransformCrossfade.currentFrame++;
                    return(false);
                }
            }
            // generate frames if needed and show the current animation frame
            currentAnimation.GenerateFrame(baseMesh, currentFrame);
            currentAnimation.DisplayFrame(this, currentFrame, previousFrame);
            return(true);
        }
예제 #2
0
        public void UpdateTick(float time)
        {
            if (initialized == false)
            {
                return;
            }
            MeshAnimation cAnim = currentAnimation;

            if ((isVisible == false && updateWhenOffscreen == false) || isPaused || speed == 0 || cAnim.playbackSpeed == 0)             // return if offscreen or crossfading
            {
                return;
            }
            // if the speed is below the normal playback speed, wait until the next frame can display
            float lodFPS      = LODLevels.Length > currentLodLevel ? LODLevels[currentLodLevel].fps : FPS;
            float totalSpeed  = Mathf.Abs(cAnim.playbackSpeed * speed);
            float tickRate    = Mathf.Max(0.0001f, 1f / lodFPS / totalSpeed);
            float actualDelta = time - lastFrameTime;
            bool  finished    = false;

            float pingPongMult = pingPong ? -1 : 1;

            if (speed * cAnim.playbackSpeed < 0)
            {
                currentAnimTime -= actualDelta * pingPongMult * totalSpeed;
            }
            else
            {
                currentAnimTime += actualDelta * pingPongMult * totalSpeed;
            }

            if (currentAnimTime < 0)
            {
                currentAnimTime = cAnim.length;
                finished        = true;
            }
            else if (currentAnimTime > cAnim.length)
            {
                if (cAnim.wrapMode == WrapMode.Loop)
                {
                    currentAnimTime = 0;
                }
                finished = true;
            }

            nextTick      = time + tickRate;
            lastFrameTime = time;

            float normalizedTime = currentAnimTime / cAnim.length;
            int   previousFrame  = currentFrame;

            currentFrame = Mathf.Min(Mathf.RoundToInt(normalizedTime * cAnim.totalFrames), cAnim.totalFrames - 1);

            // do WrapMode.PingPong
            if (cAnim.wrapMode == WrapMode.PingPong)
            {
                if (finished)
                {
                    pingPong = !pingPong;
                }
            }

            if (finished)
            {
                bool stopUpdate = false;
                if (queuedAnims != null && queuedAnims.Count > 0)
                {
                    Play(queuedAnims.Dequeue());
                    stopUpdate = true;
                }
                else if (cAnim.wrapMode != WrapMode.Loop && cAnim.wrapMode != WrapMode.PingPong)
                {
                    nextTick   = float.MaxValue;
                    stopUpdate = true;
                }
                if (OnAnimationFinished != null)
                {
                    OnAnimationFinished(cAnim.animationName);
                }
                if (stopUpdate)
                {
                    FireAnimationEvents(cAnim, totalSpeed, finished);
                    return;
                }
            }

            // generate frames if needed and show the current animation frame
            cAnim.GenerateFrameIfNeeded(baseMesh, currentFrame);

            // if crossfading, lerp the vertices to the next frame
            if (currentCrossFade.isFading)
            {
                if (currentCrossFade.currentFrame >= currentCrossFade.framesNeeded)
                {
                    currentFrame    = 0;
                    previousFrame   = -1;
                    currentAnimTime = 0;
                    ReturnCrossfadeToPool();
                }
                else
                {
#if !THREADS_ENABLED
                    GenerateCrossfadeFrame();
#endif
                    if (currentCrossFade.generatedFrame >= currentCrossFade.currentFrame)
                    {
                        if (crossFadeMesh == null)
                        {
                            crossFadeMesh = GetCrossfadeFromPool();
                        }
                        crossFadeMesh.vertices = currentCrossFade.frame.positions;
                        crossFadeMesh.bounds   = currentCrossFade.frame.bounds;
                        if (recalculateCrossfadeNormals)
                        {
                            crossFadeMesh.RecalculateNormals();
                        }
                        meshFilter.sharedMesh = crossFadeMesh;
                        currentCrossFade.ReturnFrame();
                        currentCrossFade.currentFrame++;
                        if (currentCrossFade.currentFrame < currentCrossFade.framesNeeded)
                        {
                            EnqueueAnimatorForCrossfade(this);
                        }
                        // move exposed transforms
                        bool exposedTransforms = childMap != null;
                        bool applyRootMotion   = cAnim.rootMotionMode == MeshAnimation.RootMotionMode.AppliedToTransform;
                        if (exposedTransforms || applyRootMotion)
                        {
                            float         delta     = currentCrossFade.currentFrame / (float)currentCrossFade.framesNeeded;
                            MeshFrameData fromFrame = currentCrossFade.fromFrame;
                            MeshFrameData toFrame   = currentCrossFade.toFrame;
                            // move exposed transforms
                            if (exposedTransforms)
                            {
                                for (int i = 0; i < cAnim.exposedTransforms.Length; i++)
                                {
                                    Transform child = null;
                                    if (fromFrame.exposedTransforms.Length <= i || toFrame.exposedTransforms.Length <= i)
                                    {
                                        continue;
                                    }
                                    if (childMap != null && childMap.TryGetValue(cAnim.exposedTransforms[i], out child))
                                    {
                                        Matrix4x4 f = fromFrame.exposedTransforms[i];
                                        Matrix4x4 t = toFrame.exposedTransforms[i];
                                        Matrix4x4 c = MatrixLerp(f, t, delta);
                                        MatrixUtils.FromMatrix4x4(child, c);
                                    }
                                }
                            }
                            // apply root motion
                            if (applyRootMotion)
                            {
                                Vector3    pos = Vector3.Lerp(fromFrame.rootMotionPosition, toFrame.rootMotionPosition, delta);
                                Quaternion rot = Quaternion.Lerp(fromFrame.rootMotionRotation, toFrame.rootMotionRotation, delta);
                                transform.Translate(pos, Space.Self);
                                transform.Rotate(rot.eulerAngles * Time.deltaTime, Space.Self);
                            }
                        }
                    }
                }
            }
            if (currentCrossFade.isFading == false)
            {
                cAnim.DisplayFrame(meshFilter, currentFrame, previousFrame);
                if (currentFrame != previousFrame)
                {
                    bool exposedTransforms = childMap != null;
                    bool applyRootMotion   = cAnim.rootMotionMode == MeshAnimation.RootMotionMode.AppliedToTransform;
                    if (exposedTransforms || applyRootMotion)
                    {
                        MeshFrameData frame = cAnim.GetNearestFrame(currentFrame);
                        // move exposed transforms
                        if (exposedTransforms)
                        {
                            for (int i = 0; i < cAnim.exposedTransforms.Length; i++)
                            {
                                Transform child = null;
                                if (frame.exposedTransforms.Length > i && childMap != null && childMap.TryGetValue(cAnim.exposedTransforms[i], out child))
                                {
                                    MatrixUtils.FromMatrix4x4(child, frame.exposedTransforms[i]);
                                }
                            }
                        }
                        // apply root motion
                        if (applyRootMotion)
                        {
                            if (previousFrame > currentFrame)
                            {
                                // animation looped around, apply motion for skipped frames at the end of the animation
                                for (int i = previousFrame + 1; i < cAnim.frames.Length; i++)
                                {
                                    MeshFrameData rootFrame = cAnim.GetNearestFrame(i);
                                    transform.Translate(rootFrame.rootMotionPosition, Space.Self);
                                    transform.Rotate(rootFrame.rootMotionRotation.eulerAngles * Time.deltaTime, Space.Self);
                                }
                                // now apply motion from first frame to current frame
                                for (int i = 0; i <= currentFrame; i++)
                                {
                                    MeshFrameData rootFrame = cAnim.GetNearestFrame(i);
                                    transform.Translate(rootFrame.rootMotionPosition, Space.Self);
                                    transform.Rotate(rootFrame.rootMotionRotation.eulerAngles * Time.deltaTime, Space.Self);
                                }
                            }
                            else
                            {
                                for (int i = previousFrame + 1; i <= currentFrame; i++)
                                {
                                    MeshFrameData rootFrame = cAnim.GetNearestFrame(i);
                                    transform.Translate(rootFrame.rootMotionPosition, Space.Self);
                                    transform.Rotate(rootFrame.rootMotionRotation.eulerAngles * Time.deltaTime, Space.Self);
                                }
                            }
                        }
                    }
                }
            }
            if (OnFrameUpdated != null)
            {
                OnFrameUpdated();
            }

            FireAnimationEvents(cAnim, totalSpeed, finished);

            // update the lod level if needed
            if (LODLevels.Length > 0 && (LODCamera != null || Camera.main))
            {
                if (LODCamera == null)
                {
                    LODCamera = Camera.main.transform;
                }
                float dis      = (LODCamera.position - mTransform.position).sqrMagnitude;
                int   lodLevel = 0;
                for (int i = 0; i < LODLevels.Length; i++)
                {
                    if (dis > LODLevels[i].distance * LODLevels[i].distance)
                    {
                        lodLevel = i;
                    }
                }
                if (currentLodLevel != lodLevel)
                {
                    currentLodLevel = lodLevel;
                }
            }
        }
예제 #3
0
        /// <summary>
        /// The main update loop called from the MeshAnimatorManager
        /// </summary>
        /// <param name="time">Current time</param>
        public void UpdateTick(float time)
        {
            if (initialized == false)
            {
                return;
            }
            if (animationCount == 0)
            {
                return;
            }
            if (currentAnimIndex < 0 || currentAnimIndex > animationCount)
            {
                if (defaultAnimation != null)
                {
                    Play(defaultAnimation.AnimationName);
                }
                else
                {
                    Play(0);
                }
            }
            if ((isVisible == false && updateWhenOffscreen == false) || isPaused || speed == 0 || currentAnimation.playbackSpeed == 0) // return if offscreen or crossfading
            {
                return;
            }
            // update the lod level if needed
            if (LODLevels.Length > 0 && time > nextLODCheck)
            {
                if (!hasLODCamera)
                {
                    int cameraCount = Camera.allCamerasCount;
                    if (cameraCount > 0)
                    {
                        Camera[] cameras = AllocatedArray <Camera> .Get(cameraCount);

                        cameraCount = Camera.GetAllCameras(cameras);
                        LODCamera   = cameras[0].transform;
                        AllocatedArray <Camera> .Return(cameras);

                        hasLODCamera = true;
                    }
                }
                if (hasLODCamera)
                {
                    float dis      = (LODCamera.position - mTransform.position).sqrMagnitude;
                    int   lodLevel = 0;
                    for (int i = 0; i < LODLevels.Length; i++)
                    {
                        if (dis > LODLevels[i].distanceSquared)
                        {
                            lodLevel = i;
                        }
                    }
                    if (currentLodLevel != lodLevel)
                    {
                        currentLodLevel = lodLevel;
                    }
                }
                nextLODCheck = time + UnityEngine.Random.Range(0.5f, 1.5f);
            }
            // if the speed is below the normal playback speed, wait until the next frame can display
            float lodFPS = LODLevels.Length > currentLodLevel ? LODLevels[currentLodLevel].fps : FPS;

            if (lodFPS == 0.0f)
            {
                return;
            }
            float totalSpeed     = Math.Abs(currentAnimation.playbackSpeed * speed);
            float calculatedTick = 1f / lodFPS / totalSpeed;
            float tickRate       = 0.0001f;

            if (calculatedTick > 0.0001f)
            {
                tickRate = calculatedTick;
            }
            float actualDelta = time - lastFrameTime;
            bool  finished    = false;

            float pingPongMult = pingPong ? -1 : 1;

            if (speed * currentAnimation.playbackSpeed < 0)
            {
                currentAnimTime -= actualDelta * pingPongMult * totalSpeed;
            }
            else
            {
                currentAnimTime += actualDelta * pingPongMult * totalSpeed;
            }

            if (currentAnimTime < 0)
            {
                currentAnimTime = currentAnimation.length;
                finished        = true;
            }
            else if (currentAnimTime > currentAnimation.length)
            {
                if (currentAnimation.wrapMode == WrapMode.Loop)
                {
                    currentAnimTime = currentAnimTime - currentAnimation.length;
                }
                finished = true;
            }

            nextTick      = time + tickRate;
            lastFrameTime = time;

            float normalizedTime = currentAnimTime / currentAnimation.length;
            int   previousFrame  = currentFrame;
            int   totalFrames    = currentAnimation.TotalFrames;

            currentFrame = Math.Min((int)Math.Round(normalizedTime * totalFrames), totalFrames - 1);

            // do WrapMode.PingPong
            if (currentAnimation.wrapMode == WrapMode.PingPong)
            {
                if (finished)
                {
                    pingPong = !pingPong;
                }
            }

            if (finished)
            {
                bool stopUpdate = false;
                if (queuedAnims != null && queuedAnims.Count > 0)
                {
                    Play(queuedAnims.Dequeue());
                    stopUpdate = true;
                }
                else if (currentAnimation.wrapMode != WrapMode.Loop && currentAnimation.wrapMode != WrapMode.PingPong)
                {
                    nextTick   = float.MaxValue;
                    stopUpdate = true;
                }
                if (stopUpdate)
                {
                    isPaused = true;
                }
                if (OnAnimationFinished != null)
                {
                    OnAnimationFinished(currentAnimation.AnimationName);
                }
                OnAnimationCompleted(stopUpdate);
                if (stopUpdate)
                {
                    FireAnimationEvents(currentAnimation, totalSpeed, finished);
                    return;
                }
            }

            bool updateFrameTransforms = DisplayFrame(previousFrame);

            if (updateFrameTransforms && currentFrame != previousFrame)
            {
                bool applyRootMotion = currentAnimation.rootMotionMode == RootMotionMode.AppliedToTransform;
                if (hasExposedTransforms || applyRootMotion)
                {
                    MeshFrameDataBase fromFrame   = currentAnimation.GetNearestFrame(currentFrame);
                    MeshFrameDataBase targetFrame = null;
                    int   frameGap    = currentFrame % currentAnimation.FrameSkip;
                    bool  needsInterp = actualDelta > 0 && frameGap != 0;
                    float blendDelta  = 0;
                    if (needsInterp)
                    {
                        blendDelta = currentAnimation.GetInterpolatingFrames(currentFrame, out fromFrame, out targetFrame);
                    }
                    // move exposed transforms
                    if (hasExposedTransforms)
                    {
                        var exposedTransforms = currentAnimation.ExposedTransforms;
                        for (int i = 0; i < exposedTransforms.Length; i++)
                        {
                            Transform child = null;
                            if (fromFrame.exposedTransforms.Length > i && childMap.TryGetValue(exposedTransforms[i], out child))
                            {
                                if (needsInterp)
                                {
                                    Matrix4x4 c = MatrixLerp(fromFrame.exposedTransforms[i], targetFrame.exposedTransforms[i], blendDelta);
                                    MatrixUtils.FromMatrix4x4(child, c);
                                }
                                else
                                {
                                    MatrixUtils.FromMatrix4x4(child, fromFrame.exposedTransforms[i]);
                                }
                            }
                        }
                    }
                    // apply root motion
                    if (applyRootMotion)
                    {
                        if (previousFrame > currentFrame)
                        {
                            // animation looped around, apply motion for skipped frames at the end of the animation
                            for (int i = previousFrame + 1; i < currentAnimation.Frames.Length; i++)
                            {
                                MeshFrameDataBase rootFrame = currentAnimation.GetNearestFrame(i);
                                transform.Translate(rootFrame.rootMotionPosition, Space.Self);
                                transform.Rotate(rootFrame.rootMotionRotation.eulerAngles * actualDelta, Space.Self);
                            }
                            // now apply motion from first frame to current frame
                            for (int i = 0; i <= currentFrame; i++)
                            {
                                MeshFrameDataBase rootFrame = currentAnimation.GetNearestFrame(i);
                                transform.Translate(rootFrame.rootMotionPosition, Space.Self);
                                transform.Rotate(rootFrame.rootMotionRotation.eulerAngles * actualDelta, Space.Self);
                            }
                        }
                        else
                        {
                            for (int i = previousFrame + 1; i <= currentFrame; i++)
                            {
                                MeshFrameDataBase rootFrame = currentAnimation.GetNearestFrame(i);
                                transform.Translate(rootFrame.rootMotionPosition, Space.Self);
                                transform.Rotate(rootFrame.rootMotionRotation.eulerAngles * actualDelta, Space.Self);
                            }
                        }
                    }
                }
            }
            if (OnFrameUpdated != null)
            {
                OnFrameUpdated();
            }

            FireAnimationEvents(currentAnimation, totalSpeed, finished);
        }