private AnimationOperation CreatePushOperation(PlayingAnimation playingAnimation) { return(AnimationOperation.NewPush(playingAnimation.Evaluator, playingAnimation.CurrentTime)); }
public override void Draw(RenderContext context) { var time = context.Time; foreach (var entity in enabledEntities) { var associatedData = entity.Value; var meshAnimation = associatedData.MeshAnimationUpdater; var animationComponent = associatedData.AnimationComponent; // Advance time for all playing animations with AutoPlay set to on foreach (var playingAnimation in animationComponent.PlayingAnimations) { if (playingAnimation.IsPlaying) { switch (playingAnimation.RepeatMode) { case AnimationRepeatMode.PlayOnce: playingAnimation.CurrentTime = TimeSpan.FromTicks(playingAnimation.CurrentTime.Ticks + (long)(time.Elapsed.Ticks * (double)playingAnimation.TimeFactor)); if (playingAnimation.CurrentTime > playingAnimation.Clip.Duration) { playingAnimation.CurrentTime = playingAnimation.Clip.Duration; } break; case AnimationRepeatMode.LoopInfinite: playingAnimation.CurrentTime = TimeSpan.FromTicks((playingAnimation.CurrentTime.Ticks + (long)(time.Elapsed.Ticks * (double)playingAnimation.TimeFactor)) % playingAnimation.Clip.Duration.Ticks); break; default: throw new ArgumentOutOfRangeException(); } } } // Regenerate animation operations animationOperations.Clear(); float totalWeight = 0.0f; for (int index = 0; index < animationComponent.PlayingAnimations.Count; index++) { var playingAnimation = animationComponent.PlayingAnimations[index]; var animationWeight = playingAnimation.Weight; // Skip animation with 0.0f weight if (animationWeight == 0.0f) { continue; } // Default behavior for linea blending (it will properly accumulate multiple blending with their cumulative weight) totalWeight += animationWeight; float currentBlend = animationWeight / totalWeight; if (playingAnimation.BlendOperation == AnimationBlendOperation.Add || playingAnimation.BlendOperation == AnimationBlendOperation.Subtract) { // Additive or substractive blending will use the weight as is (and reset total weight with it) currentBlend = animationWeight; totalWeight = animationWeight; } // Create evaluator var evaluator = playingAnimation.Evaluator; if (evaluator == null) { evaluator = animationComponent.Blender.CreateEvaluator(playingAnimation.Clip); playingAnimation.Evaluator = evaluator; } animationOperations.Add(CreatePushOperation(playingAnimation)); if (animationOperations.Count >= 2) { animationOperations.Add(AnimationOperation.NewBlend(playingAnimation.BlendOperation, currentBlend)); } } if (animationOperations.Count > 0) { // Animation blending animationComponent.Blender.Compute(animationOperations, ref associatedData.AnimationClipResult); // Update animation data meshAnimation.Update(associatedData.ModelComponent.ModelViewHierarchy, associatedData.AnimationClipResult); } else { // If nothing is playing, reset to bind pose associatedData.ModelComponent.ModelViewHierarchy.ResetInitialValues(); } // Update weight animation for (int index = 0; index < animationComponent.PlayingAnimations.Count; index++) { var playingAnimation = animationComponent.PlayingAnimations[index]; if (playingAnimation.RemainingTime > TimeSpan.Zero) { playingAnimation.Weight += (playingAnimation.WeightTarget - playingAnimation.Weight) * ((float)time.Elapsed.Ticks / playingAnimation.RemainingTime.Ticks); playingAnimation.RemainingTime -= time.Elapsed; if (playingAnimation.RemainingTime <= TimeSpan.Zero) { playingAnimation.Weight = playingAnimation.WeightTarget; } } else if (playingAnimation.Weight / totalWeight <= 0.01f) { animationComponent.PlayingAnimations.RemoveAt(index--); var evaluator = playingAnimation.Evaluator; if (evaluator != null) { animationComponent.Blender.ReleaseEvaluator(evaluator); playingAnimation.Evaluator = null; } } } } }
private void ApplyAnimationOperation(ref AnimationOperation animationOperation) { switch (animationOperation.Type) { case AnimationOperationType.Blend: { // Blend stack[last - 1] and stack[last] into stack[last - 1], then pop stack[last] var op2 = animationStack.Pop(); var op1 = animationStack.Peek(); Blend(animationOperation.BlendOperation, animationOperation.BlendFactor, op1, op2, op1); FreeIntermediateResult(op2); } break; case AnimationOperationType.Push: { var op = AllocateIntermediateResult(); animationOperation.Evaluator.Compute((CompressedTimeSpan)animationOperation.Time, op); animationStack.Push(op); } break; case AnimationOperationType.Pop: { var op = animationStack.Pop(); animationOperation.Evaluator.AddCurveValues((CompressedTimeSpan)animationOperation.Time, op); } break; } }