private void ResampleTransition(AnimatorStateTransition transition, AvatarMask layerMask, TransitionInfo info, Animator previewObject)
{
m_IsResampling = true;
m_MustResample = false;
m_ValidTransition = true;
bool resetTimeSettings = m_RefTransition != transition;
m_RefTransition = transition;
m_RefTransitionInfo = info;
m_LayerMask = layerMask;
if (m_AvatarPreview != null)
{
m_AvatarPreview.OnDestroy();
m_AvatarPreview = null;
}
ClearController();
Motion sourceStateMotion = m_RefSrcState.motion;
Init(previewObject, sourceStateMotion != null ? sourceStateMotion : m_RefDstState.motion);
if (m_Controller == null) // did not create controller
{
m_IsResampling = false;
return;
}
// since transform might change during sampling, and could alter the default valuesarray, and break recording
m_AvatarPreview.Animator.allowConstantClipSamplingOptimization = false;
/// sample all frames
m_StateMachine.defaultState = m_DstState;
m_Transition.mute = true;
AnimatorController.SetAnimatorController(m_AvatarPreview.Animator, m_Controller);
m_AvatarPreview.Animator.Update(0.00001f);
WriteParametersInController();
m_AvatarPreview.Animator.SetLayerWeight(m_LayerIndex, 1);
float nextStateDuration = m_AvatarPreview.Animator.GetCurrentAnimatorStateInfo(m_LayerIndex).length;
m_StateMachine.defaultState = m_SrcState;
m_Transition.mute = false;
AnimatorController.SetAnimatorController(m_AvatarPreview.Animator, m_Controller);
m_AvatarPreview.Animator.Update(0.00001f);
WriteParametersInController();
m_AvatarPreview.Animator.SetLayerWeight(m_LayerIndex, 1);
float currentStateDuration = m_AvatarPreview.Animator.GetCurrentAnimatorStateInfo(m_LayerIndex).length;
if (m_LayerIndex > 0)
{
m_AvatarPreview.Animator.stabilizeFeet = false;
}
float maxDuration = (currentStateDuration * m_RefTransition.exitTime) + (m_Transition.duration * (m_RefTransition.hasFixedDuration ? 1.0f : currentStateDuration)) + nextStateDuration;
// case 546812 disable previewer if the duration is too big, otherwise it hang Unity. 2000.0f is an arbitrary choice, it can be increase if needed.
// in some case we got a m_Transition.duration == Infinity, bail out before unity hang.
if (maxDuration > 2000.0f)
{
Debug.LogWarning("Transition duration is longer than 2000 second, Disabling previewer.");
m_ValidTransition = false;
m_IsResampling = false;
return;
}
float effectiveCurrentStatetime = m_RefTransition.exitTime > 0 ? currentStateDuration * m_RefTransition.exitTime : currentStateDuration;
// We want 30 samples/sec, maxed at 300 sample for very long state, and very short animation like 1 frame should at least get 5 sample
float currentStateStepTime = effectiveCurrentStatetime > 0 ? Mathf.Min(Mathf.Max(effectiveCurrentStatetime / 300.0f, 1.0f / 30.0f), effectiveCurrentStatetime / 5.0f) : 1.0f / 30.0f;
float nextStateStepTime = nextStateDuration > 0 ? Mathf.Min(Mathf.Max(nextStateDuration / 300.0f, 1.0f / 30.0f), nextStateDuration / 5.0f) : 1.0f / 30.0f;
currentStateStepTime = Mathf.Max(currentStateStepTime, maxDuration / 600.0f);
nextStateStepTime = Mathf.Max(nextStateStepTime, maxDuration / 600.0f);
float stepTime = currentStateStepTime;
float currentTime = 0.0f;
bool hasStarted = false;
bool hasTransitioned = false;
bool hasFinished = false;
//For transitions with exit time == 0, skip to end of clip so transition happens on first frame
if (m_RefTransition.exitTime == 0)
{
m_AvatarPreview.Animator.CrossFade(0, 0f, 0, 0.9999f);
}
m_AvatarPreview.Animator.StartRecording(-1);
m_LeftStateWeightA = 0;
m_LeftStateTimeA = 0;
m_AvatarPreview.Animator.Update(0.0f);
while (!hasFinished && currentTime < maxDuration)
{
m_AvatarPreview.Animator.Update(stepTime);
AnimatorStateInfo currentState = m_AvatarPreview.Animator.GetCurrentAnimatorStateInfo(m_LayerIndex);
currentTime += stepTime;
if (!hasStarted)
{
m_LeftStateWeightA = m_LeftStateWeightB = currentState.normalizedTime;
m_LeftStateTimeA = m_LeftStateTimeB = currentTime;
hasStarted = true;
}
if (hasTransitioned && currentTime >= maxDuration)
{
hasFinished = true;
}
if (!hasTransitioned && currentState.IsName(m_DstState.name))
{
m_RightStateWeightA = currentState.normalizedTime;
m_RightStateTimeA = currentTime;
hasTransitioned = true;
}
if (!hasTransitioned)
{
m_LeftStateWeightB = currentState.normalizedTime;
m_LeftStateTimeB = currentTime;
}
if (hasTransitioned)
{
m_RightStateWeightB = currentState.normalizedTime;
m_RightStateTimeB = currentTime;
}
if (m_AvatarPreview.Animator.IsInTransition(m_LayerIndex))
{
stepTime = nextStateStepTime;
}
}
float endTime = currentTime;
m_AvatarPreview.Animator.StopRecording();
if (Mathf.Approximately(m_LeftStateWeightB, m_LeftStateWeightA) || Mathf.Approximately(m_RightStateWeightB, m_RightStateWeightA))
{
Debug.LogWarning("Difference in effective length between states is too big. Transition preview will be disabled.");
m_ValidTransition = false;
m_IsResampling = false;
return;
}
float leftDuration = (m_LeftStateTimeB - m_LeftStateTimeA) / (m_LeftStateWeightB - m_LeftStateWeightA);
float rightDuration = (m_RightStateTimeB - m_RightStateTimeA) / (m_RightStateWeightB - m_RightStateWeightA);
if (m_MustSampleMotions)
{
// Do this as infrequently as possible
m_MustSampleMotions = false;
m_SrcPivotList.Clear();
m_DstPivotList.Clear();
stepTime = nextStateStepTime;
m_StateMachine.defaultState = m_DstState;
m_Transition.mute = true;
AnimatorController.SetAnimatorController(m_AvatarPreview.Animator, m_Controller);
m_AvatarPreview.Animator.Update(0.0f);
m_AvatarPreview.Animator.SetLayerWeight(m_LayerIndex, 1);
m_AvatarPreview.Animator.Update(0.0000001f);
WriteParametersInController();
currentTime = 0.0f;
while (currentTime <= rightDuration)
{
TimelineControl.PivotSample sample = new TimelineControl.PivotSample();
sample.m_Time = currentTime;
sample.m_Weight = m_AvatarPreview.Animator.pivotWeight;
m_DstPivotList.Add(sample);
m_AvatarPreview.Animator.Update(stepTime * 2);
currentTime += stepTime * 2;
}
stepTime = currentStateStepTime;
m_StateMachine.defaultState = m_SrcState;
m_Transition.mute = true;
AnimatorController.SetAnimatorController(m_AvatarPreview.Animator, m_Controller);
m_AvatarPreview.Animator.Update(0.0000001f);
WriteParametersInController();
m_AvatarPreview.Animator.SetLayerWeight(m_LayerIndex, 1);
currentTime = 0.0f;
while (currentTime <= leftDuration)
{
TimelineControl.PivotSample sample = new TimelineControl.PivotSample();
sample.m_Time = currentTime;
sample.m_Weight = m_AvatarPreview.Animator.pivotWeight;
m_SrcPivotList.Add(sample);
m_AvatarPreview.Animator.Update(stepTime * 2);
currentTime += stepTime * 2;
}
m_Transition.mute = false;
AnimatorController.SetAnimatorController(m_AvatarPreview.Animator, m_Controller);
m_AvatarPreview.Animator.Update(0.0000001f);
WriteParametersInController();
}
m_Timeline.StopTime = m_AvatarPreview.timeControl.stopTime = endTime;
m_AvatarPreview.timeControl.currentTime = m_Timeline.Time;
if (resetTimeSettings)
{
m_Timeline.Time = m_Timeline.StartTime = m_AvatarPreview.timeControl.currentTime = m_AvatarPreview.timeControl.startTime = 0;
m_Timeline.ResetRange();
}
m_AvatarPreview.Animator.StartPlayback();
m_AvatarPreview.Animator.playbackTime = 0f;
m_AvatarPreview.Animator.Update(0f);
m_AvatarPreview.ResetPreviewFocus();
m_IsResampling = false;
}