private void FireAnimationEvents(MeshAnimation cAnim, float totalSpeed, bool finished)
 {
     if (cAnim.events.Length > 0 && eventReciever != null && previousEventFrame != currentFrame)
     {
         if (finished)
         {
             if (totalSpeed < 0)
             {
                 // fire off animation events, including skipped frames
                 for (int i = previousEventFrame; i >= 0; i++)
                 {
                     cAnim.FireEvents(eventReciever, i);
                 }
                 previousEventFrame = 0;
             }
             else
             {
                 // fire off animation events, including skipped frames
                 for (int i = previousEventFrame; i <= cAnim.totalFrames; i++)
                 {
                     cAnim.FireEvents(eventReciever, i);
                 }
                 previousEventFrame = -1;
             }
             return;
         }
         else
         {
             if (totalSpeed < 0)
             {
                 // fire off animation events, including skipped frames
                 for (int i = currentFrame; i > previousEventFrame; i--)
                 {
                     cAnim.FireEvents(eventReciever, i);
                 }
             }
             else
             {
                 // fire off animation events, including skipped frames
                 for (int i = previousEventFrame + 1; i <= currentFrame; i++)
                 {
                     cAnim.FireEvents(eventReciever, i);
                 }
             }
             previousEventFrame = currentFrame;
         }
     }
 }
Exemple #2
0
 /// <summary>
 /// Play an animation by index
 /// </summary>
 /// <param name="index">Index of the animation</param>
 public void Play(int index)
 {
     if (index < 0 || animations.Length <= index || currentAnimIndex == index)
     {
         return;
     }
     if (queuedAnims != null)
     {
         queuedAnims.Clear();
     }
     currentAnimIndex   = index;
     currentAnimation   = animations[currentAnimIndex];
     currentFrame       = 0;
     currentAnimTime    = 0;
     previousEventFrame = -1;
     pingPong           = false;
     isPaused           = false;
     nextTick           = Time.time;
 }
        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;
                }
            }
        }
Exemple #4
0
        private void Start()
        {
            if (animations.Length == 0)
            {
                Debug.LogWarning("No animations for MeshAnimator on object: " + name + ". Disabling.", this);
                this.enabled = false;
                return;
            }

            for (int i = 0; i < animations.Length; i++)
            {
                MeshAnimation animation = animations[i];
                if (animation == null)
                {
                    continue;
                }
                animation.GenerateFrames(baseMesh);
                if (animation.exposedTransforms != null)
                {
                    for (int j = 0; j < animation.exposedTransforms.Length; j++)
                    {
                        string childName = animation.exposedTransforms[j];
                        if (string.IsNullOrEmpty(childName))
                        {
                            continue;
                        }
                        Transform childTransform = transform.Find(childName);
                        if (childTransform != null)
                        {
                            if (childMap == null)
                            {
                                childMap = new Dictionary <string, Transform>();
                            }
                            if (childMap.ContainsKey(childName) == false)
                            {
                                childMap.Add(childName, childTransform);
                                hasExposedTransforms = true;
                            }
                        }
                    }
                }
            }

            if (meshFilter == null)
            {
                meshFilter = GetComponent <MeshFilter>();
            }

            if (!s_meshCount.ContainsKey(baseMesh))
            {
                s_meshCount.Add(baseMesh, 1);
            }
            else
            {
                s_meshCount[baseMesh]++;
            }

            if (playAutomatically)
            {
                Play(defaultAnimation.name);
            }
            else
            {
                isPaused = true;
            }

#if THREADS_ENABLED
            if (s_crossfadeThreads.Count < MeshAnimatorManager.AnimatorCount / 15f && s_crossfadeThreads.Count < 20)
            {
                s_shutDownThreads = false;
                var t = new System.Threading.Thread(new System.Threading.ThreadStart(GenerateThreadedCrossfade));
                t.Start();
                s_crossfadeThreads.Add(t);
            }
#endif
            for (int i = 0; i < LODLevels.Length; i++)
            {
                float d = LODLevels[i].distance;
                LODLevels[i].distanceSquared = d * d;
            }
            initialized = true;
        }