Blending from ragdoll to animation bug
Hello guys! I'm trying to implement a smooth getting up from ragdoll to animation
I have:
Generic rig (Humanoid does not work correctly, thanks to my 3d artist)
Only blend tree in animator (idle, move left, move right, move forward, move backward).
What I already tried to:
Do not disable animator, just transition to empty state
t value in Lerp (from 0 to 1) work smoothly, no big steps
Instantiate a copy of my character right before cache bones to check that bones cached correctly
I Actually know how it works:
enable ragdoll and disable animator
cache all rigidbody bones
disable ragdoll and enable animator
start lerping from cached bones to animated bones in LateUpdate
It's work, but not completely. There is a awkward teleport in first frame when blending is started in LateUpdate
Here is my code with syntax highligthing https://pastebin.com/dZcVr9hZ
PushHero() is entry point method
Or the same code below
private void LateUpdate()
{
if (_isLerping == false)
return;
_lerp += GameParameters.Instance.StandUpLerpRate * Time.deltaTime;
for (int i = 0; i < _allRigidbodies.Length; i++)
{
_allRigidbodies[i].transform.localPosition = Vector3.Lerp(_fallenBonesPositions[i],
_allRigidbodies[i].transform.localPosition, _lerp);
_allRigidbodies[i].transform.rotation = Quaternion.Lerp(_fallenBonesAngles[i],
_allRigidbodies[i].transform.rotation, _lerp);
}
}
[ContextMenu("PushHero")]
public void PushHero()
{
_characterController.enabled = false;
_animator.enabled = false;
ActivateRagdoll();
_pushBone.AddForce((-transform.forward + Vector3.up) * GameParameters.Instance.PushForce,
ForceMode.Impulse);
StartCoroutine(ReturnToIdlePositionAfterSleepTime());
}
private void ActivateRagdoll()
{
for (int i = 0; i < _allRigidbodies.Length; i++)
{
_allRigidbodies[i].isKinematic = false;
}
}
private IEnumerator ReturnToIdlePositionAfterSleepTime()
{
yield return new WaitForSeconds(GameParameters.Instance.RagdollSleepTime);
DeactivateRagdoll();
CacheFallenBones();
ResetArmatureToZeroAndMovePrefabToArmature();
_characterController.enabled = true;
_animator.enabled = true;
_isLerping = true;
_lerp = 0;
while (_lerp < 1)
{
yield return null;
}
_isLerping = false;
}
private void CacheFallenBones()
{
_fallenBonesPositions = new Vector3[_allRigidbodies.Length];
_fallenBonesAngles = new Quaternion[_allRigidbodies.Length];
for (int i = 0; i < _allRigidbodies.Length; i++)
{
_fallenBonesPositions[i] = _allRigidbodies[i].transform.localPosition;
_fallenBonesAngles[i] = Quaternion.Euler(_allRigidbodies[i].transform.localEulerAngles);
}
}
private void ResetArmatureToZeroAndMovePrefabToArmature()
{
var armatureGlobalPosition = _rootBone.position;
transform.position = armatureGlobalPosition;
_rootBone.localPosition = Vector3.zero;
}
private void DeactivateRagdoll()
{
for (int i = 0; i < _allRigidbodies.Length; i++)
{
_allRigidbodies[i].isKinematic = true;
}
}