// NOTE: This function is called at runtime and edit time. Keep that in mind when setting the values of properties. public override void ProcessFrame (Playable playable, FrameData info, object playerData) { var spineComponent = playerData as SkeletonAnimation; if (spineComponent == null) return; var skeleton = spineComponent.Skeleton; var state = spineComponent.AnimationState; if (!Application.isPlaying) { #if SPINE_EDITMODEPOSE PreviewEditModePose(playable, spineComponent); #endif return; } int inputCount = playable.GetInputCount(); // Ensure correct buffer size. if (this.lastInputWeights == null || this.lastInputWeights.Length < inputCount) { this.lastInputWeights = new float[inputCount]; for (int i = 0; i < inputCount; i++) this.lastInputWeights[i] = default(float); } var lastInputWeights = this.lastInputWeights; // Check all clips. If a clip that was weight 0 turned into weight 1, call SetAnimation. for (int i = 0; i < inputCount; i++) { float lastInputWeight = lastInputWeights[i]; float inputWeight = playable.GetInputWeight(i); bool trackStarted = inputWeight > lastInputWeight; lastInputWeights[i] = inputWeight; if (trackStarted) { ScriptPlayable<SpineAnimationStateBehaviour> inputPlayable = (ScriptPlayable<SpineAnimationStateBehaviour>)playable.GetInput(i); SpineAnimationStateBehaviour clipData = inputPlayable.GetBehaviour(); if (clipData.animationReference == null) { float mixDuration = clipData.customDuration ? clipData.mixDuration : state.Data.DefaultMix; state.SetEmptyAnimation(trackIndex, mixDuration); } else { if (clipData.animationReference.Animation != null) { Spine.TrackEntry trackEntry = state.SetAnimation(trackIndex, clipData.animationReference.Animation, clipData.loop); //trackEntry.TrackTime = (float)inputPlayable.GetTime(); // More accurate time-start? trackEntry.EventThreshold = clipData.eventThreshold; trackEntry.DrawOrderThreshold = clipData.drawOrderThreshold; trackEntry.AttachmentThreshold = clipData.attachmentThreshold; if (clipData.customDuration) trackEntry.MixDuration = clipData.mixDuration; } //else Debug.LogWarningFormat("Animation named '{0}' not found", clipData.animationName); } // Ensure that the first frame ends with an updated mesh. spineComponent.Update(0); spineComponent.LateUpdate(); } } }
public void PreviewEditModePose(Playable playable, SkeletonAnimation spineComponent) { if (!Application.isPlaying && (spineComponent != null)) { int inputCount = playable.GetInputCount <Playable>(); int inputPort = -1; for (int i = 0; i < inputCount; i++) { if (playable.GetInputWeight <Playable>(i) >= 1f) { inputPort = i; } } if (inputPort != -1) { ScriptPlayable <SpineAnimationStateBehaviour> input = (ScriptPlayable <SpineAnimationStateBehaviour>)playable.GetInput <Playable>(inputPort); SpineAnimationStateBehaviour behaviour = input.GetBehaviour(); Skeleton skeleton = spineComponent.Skeleton; if ((behaviour.animationReference != null) && (spineComponent.SkeletonDataAsset.GetSkeletonData(true) != behaviour.animationReference.SkeletonDataAsset.GetSkeletonData(true))) { object[] args = new object[] { spineComponent.SkeletonDataAsset, behaviour.animationReference.SkeletonDataAsset }; Debug.LogWarningFormat("SpineAnimationStateMixerBehaviour tried to apply an animation for the wrong skeleton. Expected {0}. Was {1}", args); } Spine.Animation from = null; float time = 0f; bool loop = false; if ((inputPort != 0) && (inputCount > 1)) { ScriptPlayable <SpineAnimationStateBehaviour> playable3 = (ScriptPlayable <SpineAnimationStateBehaviour>)playable.GetInput <Playable>((inputPort - 1)); SpineAnimationStateBehaviour behaviour2 = playable3.GetBehaviour(); from = behaviour2.animationReference.Animation; time = (float)playable3.GetTime <ScriptPlayable <SpineAnimationStateBehaviour> >(); loop = behaviour2.loop; } Spine.Animation animation = behaviour.animationReference.Animation; float num6 = (float)input.GetTime <ScriptPlayable <SpineAnimationStateBehaviour> >(); float mixDuration = behaviour.mixDuration; if (!behaviour.customDuration && (from != null)) { mixDuration = spineComponent.AnimationState.Data.GetMix(from, animation); } if (((from != null) && (mixDuration > 0f)) && (num6 < mixDuration)) { skeleton.SetToSetupPose(); float alpha = 1f - (num6 / mixDuration); alpha = (alpha <= 0.5f) ? (alpha * 2f) : 1f; from.Apply(skeleton, 0f, time, loop, null, alpha, MixPose.Setup, MixDirection.Out); animation.Apply(skeleton, 0f, num6, behaviour.loop, null, num6 / mixDuration, MixPose.Current, MixDirection.In); } else { skeleton.SetToSetupPose(); animation.PoseSkeleton(skeleton, num6, behaviour.loop); } } } }
public override void ProcessFrame(Playable playable, FrameData info, object playerData) { SkeletonAnimation spineComponent = playerData as SkeletonAnimation; if (spineComponent != null) { Skeleton skeleton = spineComponent.Skeleton; Spine.AnimationState animationState = spineComponent.AnimationState; if (!Application.isPlaying) { this.PreviewEditModePose(playable, spineComponent); } else { int inputCount = playable.GetInputCount <Playable>(); if ((this.lastInputWeights == null) || (this.lastInputWeights.Length < inputCount)) { this.lastInputWeights = new float[inputCount]; for (int j = 0; j < inputCount; j++) { this.lastInputWeights[j] = 0f; } } float[] lastInputWeights = this.lastInputWeights; for (int i = 0; i < inputCount; i++) { float num4 = lastInputWeights[i]; float inputWeight = playable.GetInputWeight <Playable>(i); bool flag = inputWeight > num4; lastInputWeights[i] = inputWeight; if (flag) { SpineAnimationStateBehaviour behaviour = ((ScriptPlayable <SpineAnimationStateBehaviour>)playable.GetInput <Playable>(i)).GetBehaviour(); if (behaviour.animationReference == null) { float mixDuration = !behaviour.customDuration ? animationState.Data.DefaultMix : behaviour.mixDuration; animationState.SetEmptyAnimation(0, mixDuration); } else if (behaviour.animationReference.Animation != null) { TrackEntry entry = animationState.SetAnimation(0, behaviour.animationReference.Animation, behaviour.loop); entry.EventThreshold = behaviour.eventThreshold; entry.DrawOrderThreshold = behaviour.drawOrderThreshold; entry.AttachmentThreshold = behaviour.attachmentThreshold; if (behaviour.customDuration) { entry.MixDuration = behaviour.mixDuration; } } spineComponent.Update(0f); spineComponent.LateUpdate(); } } } } }
float GetCustomMixDuration(SpineAnimationStateBehaviour clipData) { if (clipData.useBlendDuration) { TimelineClip clip = clipData.timelineClip; return((float)Math.Max(clip.blendInDuration, clip.easeInDuration)); } else { return(clipData.mixDuration); } }
public void PreviewEditModePose(Playable playable, ISkeletonComponent skeletonComponent, IAnimationStateComponent animationStateComponent, SkeletonAnimation skeletonAnimation, SkeletonGraphic skeletonGraphic) { if (Application.isPlaying) { return; } if (animationStateComponent.IsNullOrDestroyed() || skeletonComponent == null) { return; } int inputCount = playable.GetInputCount(); int lastNonZeroWeightTrack = -1; for (int i = 0; i < inputCount; i++) { float inputWeight = playable.GetInputWeight(i); if (inputWeight > 0) { lastNonZeroWeightTrack = i; } } if (lastNonZeroWeightTrack != -1) { ScriptPlayable <SpineAnimationStateBehaviour> inputPlayableClip = (ScriptPlayable <SpineAnimationStateBehaviour>)playable.GetInput(lastNonZeroWeightTrack); SpineAnimationStateBehaviour clipData = inputPlayableClip.GetBehaviour(); var skeleton = skeletonComponent.Skeleton; bool skeletonDataMismatch = clipData.animationReference != null && clipData.animationReference.SkeletonDataAsset && skeletonComponent.SkeletonDataAsset.GetSkeletonData(true) != clipData.animationReference.SkeletonDataAsset.GetSkeletonData(true); if (skeletonDataMismatch) { Debug.LogWarningFormat("SpineAnimationStateMixerBehaviour tried to apply an animation for the wrong skeleton. Expected {0}. Was {1}", skeletonComponent.SkeletonDataAsset, clipData.animationReference.SkeletonDataAsset); } // Getting the from-animation here because it's required to get the mix information from AnimationStateData. Animation fromAnimation = null; float fromClipTime = 0; bool fromClipLoop = false; if (lastNonZeroWeightTrack != 0 && inputCount > 1) { var fromClip = (ScriptPlayable <SpineAnimationStateBehaviour>)playable.GetInput(lastNonZeroWeightTrack - 1); var fromClipData = fromClip.GetBehaviour(); fromAnimation = fromClipData.animationReference != null ? fromClipData.animationReference.Animation : null; fromClipTime = (float)fromClip.GetTime() * (float)fromClip.GetSpeed(); fromClipLoop = fromClipData.loop; } Animation toAnimation = clipData.animationReference != null ? clipData.animationReference.Animation : null; float toClipTime = (float)inputPlayableClip.GetTime() * (float)inputPlayableClip.GetSpeed(); float mixDuration = clipData.mixDuration; if (!clipData.customDuration && fromAnimation != null && toAnimation != null) { mixDuration = animationStateComponent.AnimationState.Data.GetMix(fromAnimation, toAnimation); } if (trackIndex == 0) { skeleton.SetToSetupPose(); } // Approximate what AnimationState might do at runtime. if (fromAnimation != null && mixDuration > 0 && toClipTime < mixDuration) { dummyAnimationState = dummyAnimationState ?? new AnimationState(skeletonComponent.SkeletonDataAsset.GetAnimationStateData()); var toEntry = dummyAnimationState.GetCurrent(0); var fromEntry = toEntry != null ? toEntry.MixingFrom : null; bool isAnimationTransitionMatch = (toEntry != null && toEntry.Animation == toAnimation && fromEntry != null && fromEntry.Animation == fromAnimation); if (!isAnimationTransitionMatch) { dummyAnimationState.ClearTracks(); fromEntry = dummyAnimationState.SetAnimation(0, fromAnimation, fromClipLoop); fromEntry.AllowImmediateQueue(); if (toAnimation != null) { toEntry = dummyAnimationState.SetAnimation(0, toAnimation, clipData.loop); toEntry.HoldPrevious = clipData.holdPrevious; } } // Update track times. fromEntry.TrackTime = fromClipTime; if (toEntry != null) { toEntry.TrackTime = toClipTime; toEntry.MixTime = toClipTime; } // Apply Pose dummyAnimationState.Update(0); dummyAnimationState.Apply(skeleton); } else { if (toAnimation != null) { toAnimation.Apply(skeleton, 0, toClipTime, clipData.loop, null, 1f, MixBlend.Setup, MixDirection.In); } } skeleton.UpdateWorldTransform(); if (skeletonAnimation) { skeletonAnimation.LateUpdate(); } else if (skeletonGraphic) { skeletonGraphic.LateUpdate(); } } // Do nothing outside of the first clip and the last clip. }
// NOTE: This function is called at runtime and edit time. Keep that in mind when setting the values of properties. public override void ProcessFrame(Playable playable, FrameData info, object playerData) { var skeletonAnimation = playerData as SkeletonAnimation; var skeletonGraphic = playerData as SkeletonGraphic; animationStateComponent = playerData as IAnimationStateComponent; var skeletonComponent = playerData as ISkeletonComponent; if (animationStateComponent.IsNullOrDestroyed() || skeletonComponent == null) { return; } var skeleton = skeletonComponent.Skeleton; var state = animationStateComponent.AnimationState; if (!Application.isPlaying) { #if SPINE_EDITMODEPOSE PreviewEditModePose(playable, skeletonComponent, animationStateComponent, skeletonAnimation, skeletonGraphic); #endif return; } int inputCount = playable.GetInputCount(); // Ensure correct buffer size. if (this.lastInputWeights == null || this.lastInputWeights.Length < inputCount) { this.lastInputWeights = new float[inputCount]; for (int i = 0; i < inputCount; i++) { this.lastInputWeights[i] = default(float); } } var lastInputWeights = this.lastInputWeights; int numStartingClips = 0; bool anyClipPlaying = false; // Check all clips. If a clip that was weight 0 turned into weight 1, call SetAnimation. for (int i = 0; i < inputCount; i++) { float lastInputWeight = lastInputWeights[i]; float inputWeight = playable.GetInputWeight(i); bool clipStarted = lastInputWeight == 0 && inputWeight > 0; if (inputWeight > 0) { anyClipPlaying = true; } lastInputWeights[i] = inputWeight; if (clipStarted && numStartingClips < 2) { ScriptPlayable <SpineAnimationStateBehaviour> clipPlayable = (ScriptPlayable <SpineAnimationStateBehaviour>)playable.GetInput(i); startingClips[numStartingClips++] = clipPlayable; } } // unfortunately order of clips can be wrong when two start at the same time, we have to sort clips if (numStartingClips == 2) { ScriptPlayable <SpineAnimationStateBehaviour> clipPlayable0 = startingClips[0]; ScriptPlayable <SpineAnimationStateBehaviour> clipPlayable1 = startingClips[1]; if (clipPlayable0.GetDuration() > clipPlayable1.GetDuration()) // swap, clip 0 ends after clip 1 { startingClips[0] = clipPlayable1; startingClips[1] = clipPlayable0; } } for (int j = 0; j < numStartingClips; ++j) { ScriptPlayable <SpineAnimationStateBehaviour> clipPlayable = startingClips[j]; SpineAnimationStateBehaviour clipData = clipPlayable.GetBehaviour(); pauseWithDirector = !clipData.dontPauseWithDirector; endAtClipEnd = !clipData.dontEndWithClip; endMixOutDuration = clipData.endMixOutDuration; if (clipData.animationReference == null) { float mixDuration = clipData.customDuration ? GetCustomMixDuration(clipData) : state.Data.DefaultMix; state.SetEmptyAnimation(trackIndex, mixDuration); } else { if (clipData.animationReference.Animation != null) { TrackEntry currentEntry = state.GetCurrent(trackIndex); Spine.TrackEntry trackEntry; float customMixDuration = clipData.customDuration ? GetCustomMixDuration(clipData) : 0.0f; if (currentEntry == null && customMixDuration > 0) { state.SetEmptyAnimation(trackIndex, 0); // ease in requires empty animation trackEntry = state.AddAnimation(trackIndex, clipData.animationReference.Animation, clipData.loop, 0); } else { trackEntry = state.SetAnimation(trackIndex, clipData.animationReference.Animation, clipData.loop); } trackEntry.EventThreshold = clipData.eventThreshold; trackEntry.DrawOrderThreshold = clipData.drawOrderThreshold; trackEntry.TrackTime = (float)clipPlayable.GetTime() * (float)clipPlayable.GetSpeed(); trackEntry.TimeScale = (float)clipPlayable.GetSpeed(); trackEntry.AttachmentThreshold = clipData.attachmentThreshold; trackEntry.HoldPrevious = clipData.holdPrevious; if (clipData.customDuration) { trackEntry.MixDuration = customMixDuration; } timelineStartedTrackEntry = trackEntry; } //else Debug.LogWarningFormat("Animation named '{0}' not found", clipData.animationName); } // Ensure that the first frame ends with an updated mesh. if (skeletonAnimation) { skeletonAnimation.Update(0); skeletonAnimation.LateUpdate(); } else if (skeletonGraphic) { skeletonGraphic.Update(0); skeletonGraphic.LateUpdate(); } } startingClips[0] = startingClips[1] = ScriptPlayable <SpineAnimationStateBehaviour> .Null; if (lastAnyClipPlaying && !anyClipPlaying) { HandleClipEnd(); } this.lastAnyClipPlaying = anyClipPlaying; }
public void PreviewEditModePose(Playable playable, SkeletonAnimation spineComponent) { if (Application.isPlaying) { return; } if (spineComponent == null) { return; } int inputCount = playable.GetInputCount(); int lastOneWeight = -1; for (int i = 0; i < inputCount; i++) { float inputWeight = playable.GetInputWeight(i); if (inputWeight >= 1) { lastOneWeight = i; } } if (lastOneWeight != -1) { ScriptPlayable <SpineAnimationStateBehaviour> inputPlayableClip = (ScriptPlayable <SpineAnimationStateBehaviour>)playable.GetInput(lastOneWeight); SpineAnimationStateBehaviour clipData = inputPlayableClip.GetBehaviour(); var skeleton = spineComponent.Skeleton; bool skeletonDataMismatch = clipData.animationReference != null && spineComponent.SkeletonDataAsset.GetSkeletonData(true) != clipData.animationReference.SkeletonDataAsset.GetSkeletonData(true); if (skeletonDataMismatch) { Debug.LogWarningFormat("SpineAnimationStateMixerBehaviour tried to apply an animation for the wrong skeleton. Expected {0}. Was {1}", spineComponent.SkeletonDataAsset, clipData.animationReference.SkeletonDataAsset); } // Getting the from-animation here because it's required to get the mix information from AnimationStateData. Animation fromAnimation = null; float fromClipTime = 0; bool fromClipLoop = false; if (lastOneWeight != 0 && inputCount > 1) { var fromClip = (ScriptPlayable <SpineAnimationStateBehaviour>)playable.GetInput(lastOneWeight - 1); var fromClipData = fromClip.GetBehaviour(); fromAnimation = fromClipData.animationReference.Animation; fromClipTime = (float)fromClip.GetTime(); fromClipLoop = fromClipData.loop; } Animation toAnimation = clipData.animationReference.Animation; float toClipTime = (float)inputPlayableClip.GetTime(); float mixDuration = clipData.mixDuration; if (!clipData.customDuration && fromAnimation != null) { mixDuration = spineComponent.AnimationState.Data.GetMix(fromAnimation, toAnimation); } // Approximate what AnimationState might do at runtime. if (fromAnimation != null && mixDuration > 0 && toClipTime < mixDuration) { skeleton.SetToSetupPose(); float fauxFromAlpha = (1f - toClipTime / mixDuration); fauxFromAlpha = fauxFromAlpha > 0.5f ? 1f : fauxFromAlpha * 2f; // fake value, but reduce dip. fromAnimation.Apply(skeleton, 0, fromClipTime, fromClipLoop, null, fauxFromAlpha, MixPose.Setup, MixDirection.Out); //fromAnimation.PoseSkeleton(skeleton, fromClipTime, fromClipLoop); toAnimation.Apply(skeleton, 0, toClipTime, clipData.loop, null, toClipTime / mixDuration, MixPose.Current, MixDirection.In); } else { skeleton.SetToSetupPose(); toAnimation.PoseSkeleton(skeleton, toClipTime, clipData.loop); } } // Do nothing outside of the first clip and the last clip. }
public void PreviewEditModePose(Playable playable, SkeletonAnimation spineComponent) { if (Application.isPlaying) { return; } if (spineComponent == null) { return; } int inputCount = playable.GetInputCount(); int lastOneWeight = -1; for (int i = 0; i < inputCount; i++) { float inputWeight = playable.GetInputWeight(i); if (inputWeight >= 1) { lastOneWeight = i; } } if (lastOneWeight != -1) { ScriptPlayable <SpineAnimationStateBehaviour> inputPlayableClip = (ScriptPlayable <SpineAnimationStateBehaviour>)playable.GetInput(lastOneWeight); SpineAnimationStateBehaviour clipData = inputPlayableClip.GetBehaviour(); var skeleton = spineComponent.Skeleton; bool skeletonDataMismatch = clipData.animationReference != null && spineComponent.SkeletonDataAsset.GetSkeletonData(true) != clipData.animationReference.SkeletonDataAsset.GetSkeletonData(true); if (skeletonDataMismatch) { Debug.LogWarningFormat("SpineAnimationStateMixerBehaviour tried to apply an animation for the wrong skeleton. Expected {0}. Was {1}", spineComponent.SkeletonDataAsset, clipData.animationReference.SkeletonDataAsset); } // Getting the from-animation here because it's required to get the mix information from AnimationStateData. Animation fromAnimation = null; float fromClipTime = 0; bool fromClipLoop = false; if (lastOneWeight != 0 && inputCount > 1) { var fromClip = (ScriptPlayable <SpineAnimationStateBehaviour>)playable.GetInput(lastOneWeight - 1); var fromClipData = fromClip.GetBehaviour(); fromAnimation = fromClipData.animationReference != null ? fromClipData.animationReference.Animation : null; fromClipTime = (float)fromClip.GetTime(); fromClipLoop = fromClipData.loop; } Animation toAnimation = clipData.animationReference != null ? clipData.animationReference.Animation : null; float toClipTime = (float)inputPlayableClip.GetTime(); float mixDuration = clipData.mixDuration; if (!clipData.customDuration && fromAnimation != null && toAnimation != null) { mixDuration = spineComponent.AnimationState.Data.GetMix(fromAnimation, toAnimation); } // Approximate what AnimationState might do at runtime. if (fromAnimation != null && mixDuration > 0 && toClipTime < mixDuration) { dummyAnimationState = dummyAnimationState ?? new AnimationState(spineComponent.skeletonDataAsset.GetAnimationStateData()); var toTrack = dummyAnimationState.GetCurrent(0); var fromTrack = toTrack != null ? toTrack.mixingFrom : null; bool isAnimationTransitionMatch = (toTrack != null && toTrack.animation == toAnimation && fromTrack != null && fromTrack.animation == fromAnimation); if (!isAnimationTransitionMatch) { dummyAnimationState.ClearTracks(); fromTrack = dummyAnimationState.SetAnimation(0, fromAnimation, fromClipLoop); fromTrack.AllowImmediateQueue(); if (toAnimation != null) { toTrack = dummyAnimationState.SetAnimation(0, toAnimation, clipData.loop); } } // Update track times. fromTrack.trackTime = fromClipTime; if (toTrack != null) { toTrack.trackTime = toClipTime; toTrack.mixTime = toClipTime; } // Apply Pose skeleton.SetToSetupPose(); dummyAnimationState.Update(0); dummyAnimationState.Apply(skeleton); } else { skeleton.SetToSetupPose(); if (toAnimation != null) { toAnimation.PoseSkeleton(skeleton, toClipTime, clipData.loop); } } } // Do nothing outside of the first clip and the last clip. }
// NOTE: This function is called at runtime and edit time. Keep that in mind when setting the values of properties. public override void ProcessFrame(Playable playable, FrameData info, object playerData) { var trackBinding = playerData as SkeletonAnimation; if (trackBinding == null) { return; } if (!Application.isPlaying) { #if SPINE_EDITMODEPOSE PreviewEditModePose(playable, trackBinding); #endif return; } int inputCount = playable.GetInputCount(); if (this.lastInputWeights == null || this.lastInputWeights.Length < inputCount) { this.lastInputWeights = new float[inputCount]; for (int i = 0; i < inputCount; i++) { this.lastInputWeights[i] = 0f; } } var lastInputWeights = this.lastInputWeights; for (int i = 0; i < inputCount; i++) { float lastInputWeight = lastInputWeights[i]; float inputWeight = playable.GetInputWeight(i); bool trackStarted = inputWeight > lastInputWeight; lastInputWeights[i] = inputWeight; if (trackStarted) { ScriptPlayable <SpineAnimationStateBehaviour> inputPlayable = (ScriptPlayable <SpineAnimationStateBehaviour>)playable.GetInput(i); SpineAnimationStateBehaviour input = inputPlayable.GetBehaviour(); Spine.Animation animation = trackBinding.Skeleton.Data.FindAnimation(input.animationName); if (animation != null) { Spine.TrackEntry trackEntry = trackBinding.AnimationState.SetAnimation(0, input.animationName, input.loop); trackEntry.EventThreshold = input.eventThreshold; trackEntry.DrawOrderThreshold = input.drawOrderThreshold; trackEntry.AttachmentThreshold = input.attachmentThreshold; if (input.customDuration) { trackEntry.MixDuration = input.mixDuration; } } else if (string.IsNullOrEmpty(input.animationName)) { float mixDuration = input.customDuration ? input.mixDuration : trackBinding.AnimationState.Data.DefaultMix; trackBinding.AnimationState.SetEmptyAnimation(0, mixDuration); continue; } // else { // Debug.LogWarningFormat("Animation named '{0}' not found", input.animationName); // } } } }
public void PreviewEditModePose(Playable playable, SkeletonAnimation trackBinding) { if (Application.isPlaying) { return; } if (trackBinding == null) { return; } int inputCount = playable.GetInputCount(); int lastOneWeight = -1; for (int i = 0; i < inputCount; i++) { float inputWeight = playable.GetInputWeight(i); if (inputWeight >= 1) { lastOneWeight = i; } } if (lastOneWeight != -1) { ScriptPlayable <SpineAnimationStateBehaviour> inputPlayableClip = (ScriptPlayable <SpineAnimationStateBehaviour>)playable.GetInput(lastOneWeight); SpineAnimationStateBehaviour clipBehaviourData = inputPlayableClip.GetBehaviour(); var skeleton = trackBinding.Skeleton; var skeletonData = trackBinding.Skeleton.Data; ScriptPlayable <SpineAnimationStateBehaviour> fromClip; Animation fromAnimation = null; float fromClipTime = 0; bool fromClipLoop = false; if (lastOneWeight != 0 && inputCount > 1) { fromClip = (ScriptPlayable <SpineAnimationStateBehaviour>)playable.GetInput(lastOneWeight - 1); var fromClipData = fromClip.GetBehaviour(); fromAnimation = skeletonData.FindAnimation(fromClipData.animationName); fromClipTime = (float)fromClip.GetTime(); fromClipLoop = fromClipData.loop; } Animation toAnimation = skeletonData.FindAnimation(clipBehaviourData.animationName); float toClipTime = (float)inputPlayableClip.GetTime(); float mixDuration = clipBehaviourData.mixDuration; if (!clipBehaviourData.customDuration && fromAnimation != null) { mixDuration = trackBinding.AnimationState.Data.GetMix(fromAnimation, toAnimation); } // Approximate what AnimationState might do at runtime. if (fromAnimation != null && mixDuration > 0 && toClipTime < mixDuration) { skeleton.SetToSetupPose(); float fauxFromAlpha = (1f - toClipTime / mixDuration); fauxFromAlpha = fauxFromAlpha > 0.5f ? 1f : fauxFromAlpha * 2f; // fake value, but reduce dip. fromAnimation.Apply(skeleton, 0, fromClipTime, fromClipLoop, null, fauxFromAlpha, MixPose.Setup, MixDirection.Out); //fromAnimation.PoseSkeleton(skeleton, fromClipTime, fromClipLoop); toAnimation.Apply(skeleton, 0, toClipTime, clipBehaviourData.loop, null, toClipTime / mixDuration, MixPose.Current, MixDirection.In); } else { skeleton.SetToSetupPose(); toAnimation.PoseSkeleton(skeleton, toClipTime, clipBehaviourData.loop); } } // Do nothing outside of the first clip and the last clip. }