public void Reset() { fromFrame = null; toFrame = null; isFading = false; endTime = 0; currentFrame = 0; generatedFrame = -1; framesNeeded = 0; ReturnFrame(); }
public override bool Equals(object obj) { if (obj is MeshFrameData) { MeshFrameData other = (MeshFrameData)obj; if (other.verts.Length != verts.Length) { return(false); } for (int i = 0; i < other.verts.Length; i++) { if (verts[i] != other.verts[i]) { return(false); } } return(true); } return(base.Equals(obj)); }
public float GetInterpolatingFrames(int frame, out MeshFrameData previousFrame, out MeshFrameData nextFrame) { bool needsInterp = frame % frameSkip != 0; if (!needsInterp) { int frameIndex = frame / frameSkip; previousFrame = frameData[frameIndex]; if (frameIndex + 1 >= frameData.Length) { nextFrame = frameData[0]; } else { nextFrame = frameData[frameIndex + 1]; } return(0); } float framePerc = (float)frame / (float)(frameSkip * frameData.Length); int skipFrame = (int)(framePerc * frameData.Length); float prevFramePerc = (float)skipFrame / (float)frameData.Length; float nextFramePerc = Mathf.Clamp01((float)(skipFrame + 1) / (float)frameData.Length); previousFrame = frameData[skipFrame]; if (skipFrame + 1 >= frameData.Length) { nextFrame = frameData[0]; } else { nextFrame = frameData[skipFrame + 1]; } float lerpVal = Mathf.Lerp(0, 1, (framePerc - prevFramePerc) / (nextFramePerc - prevFramePerc)); return(lerpVal); }
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; } } }