Can someone please help me out with this Rotation issue - My animation has the feet rotated , but when the Ik is enabled it does not take that into account.
Here is my code
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FeetGrounder : MonoBehaviour
{
//Ik Feel Position and Rotation Values
private Vector3 _rightFootPosition, _leftFootPosition, _leftFootIkPosition, _rightFootIkPosition;
private Quaternion _leftFootIkRotation, _rightFootIkRotation;
private float _lastPelvisPositionY, _lastRightFootPositionY, _lastLeftFootPositionY;
private Animator _animator;
[Header("Feet Grounder")]
public bool enableFeetIk = true;
[Range(0, 2)] [SerializeField] private float heightFromGroundRaycast = 1.14f;
[Range(0, 2)] [SerializeField] private float raycastDownDistance = 1.5f;
[SerializeField] private LayerMask enviromentLayer;
[SerializeField] private float pelvisOffset = 0f;
[Range(0, 1)] [SerializeField] private float pelvisUpAndDownSpeed = 0.28f;
[Range(0, 1)] public float feetToIkPositionSpeed = 0.5f;
public string leftFootAnimVariableName = "LeftFootCurve";
public string rightFootAnimVariableName = "RightFootCurve";
public bool useProIkFeature = false;
public bool showSolverDebug = true;
private void Start()
{
_animator = GetComponent<Animator>();
}
private void FixedUpdate()
{
if (enableFeetIk == false) {return;}
if (_animator == null) {return;}
AdjustFeetTarget(ref _rightFootPosition, HumanBodyBones.RightFoot);
AdjustFeetTarget(ref _leftFootPosition, HumanBodyBones.LeftFoot);
//find and raycast to the ground to find positions
FeetPositionSolver(_rightFootPosition,ref _rightFootIkPosition,ref _rightFootIkRotation);// handle the solver for right foot
FeetPositionSolver(_leftFootPosition, ref _leftFootIkPosition,ref _leftFootIkRotation);//Left foot Solver
}
private void OnAnimatorIK(int layerIndex)
{
if (enableFeetIk ==false) {return;}
if (_animator == null) {return;}
MovePelvisHeight();
//right foot Ik position and rotation -- utilise the pro feature here
_animator.SetIKPositionWeight(AvatarIKGoal.RightFoot,1);
if (useProIkFeature)
{
_animator.SetIKRotationWeight(AvatarIKGoal.RightFoot,_animator.GetFloat(rightFootAnimVariableName));
}
MoveFeetToIkPoint(AvatarIKGoal.RightFoot,_rightFootIkPosition,_rightFootIkRotation,ref _lastRightFootPositionY);
//Left foot Ik position and rotation -- utilise the pro feature here
_animator.SetIKPositionWeight(AvatarIKGoal.LeftFoot,1);
if (useProIkFeature)
{
_animator.SetIKRotationWeight(AvatarIKGoal.LeftFoot,_animator.GetFloat(leftFootAnimVariableName));
}
MoveFeetToIkPoint(AvatarIKGoal.LeftFoot,_leftFootIkPosition,_leftFootIkRotation,ref _lastLeftFootPositionY);
}
private void MoveFeetToIkPoint(AvatarIKGoal foot, Vector3 positionIkHolder, Quaternion rotationIkHolder,
ref float lastFootPositionY)
{
Vector3 targetIkPosition = _animator.GetIKPosition(foot);
if (positionIkHolder != Vector3.zero)
{
targetIkPosition = transform.InverseTransformPoint(targetIkPosition);
positionIkHolder = transform.InverseTransformPoint(positionIkHolder);
float yVariable = Mathf.Lerp(lastFootPositionY, positionIkHolder.y, feetToIkPositionSpeed);
targetIkPosition.y += yVariable;
lastFootPositionY = yVariable;
targetIkPosition = transform.TransformPoint(targetIkPosition);
_animator.SetIKRotation(foot, rotationIkHolder);
}
_animator.SetIKPosition(foot,targetIkPosition);
}
private void MovePelvisHeight()
{
if (_rightFootIkPosition == Vector3.zero || _leftFootIkPosition == Vector3.zero ||
_lastPelvisPositionY == 0)
{
_lastPelvisPositionY = _animator.bodyPosition.y;
return;
}
float lOffsetPosition = _leftFootIkPosition.y - transform.position.y;
float rOffsetPosition = _rightFootIkPosition.y - transform.position.y;
float totalOffset = (lOffsetPosition < rOffsetPosition) ? lOffsetPosition : rOffsetPosition;
Vector3 newPelvisPosition = _animator.bodyPosition + Vector3.up * totalOffset;
newPelvisPosition.y = Mathf.Lerp(_lastPelvisPositionY, newPelvisPosition.y, pelvisUpAndDownSpeed);
_animator.bodyPosition = newPelvisPosition;
_lastPelvisPositionY = _animator.bodyPosition.y;
}
private void FeetPositionSolver(Vector3 fromSkyPosition, ref Vector3 feetIkPositions, ref Quaternion feetIkRotations)
{
//raycast section - locating the feet position via a raycast and solving
RaycastHit feetOutHit;
if (showSolverDebug)
{
Debug.DrawLine(fromSkyPosition,fromSkyPosition + Vector3.down *
(raycastDownDistance + heightFromGroundRaycast),Color.yellow);
}
if (Physics.Raycast(fromSkyPosition, Vector3.down,
out feetOutHit, raycastDownDistance + heightFromGroundRaycast, enviromentLayer))
{
feetIkPositions = fromSkyPosition;
feetIkPositions.y = feetOutHit.point.y + pelvisOffset;
feetIkRotations = Quaternion.FromToRotation(Vector3.up, feetOutHit.normal) * transform.rotation;
return;;
}
feetIkPositions = Vector3.zero;//it didnt work
}
private void AdjustFeetTarget(ref Vector3 feetPositions, HumanBodyBones foot)
{
feetPositions = _animator.GetBoneTransform(foot).position;
feetPositions.y = transform.position.y + heightFromGroundRaycast;
}
}
I think this is where I need to add my initial foot rotation but I have no idea how to calculate the offset
private void FeetPositionSolver(Vector3 fromSkyPosition, ref Vector3 feetIkPositions, ref Quaternion feetIkRotations)
{
//raycast section - locating the feet position via a raycast and solving
RaycastHit feetOutHit;
if (showSolverDebug)
{
Debug.DrawLine(fromSkyPosition,fromSkyPosition + Vector3.down *
(raycastDownDistance + heightFromGroundRaycast),Color.yellow);
}
if (Physics.Raycast(fromSkyPosition, Vector3.down,
out feetOutHit, raycastDownDistance + heightFromGroundRaycast, enviromentLayer))
{
feetIkPositions = fromSkyPosition;
feetIkPositions.y = feetOutHit.point.y + pelvisOffset;
feetIkRotations = Quaternion.FromToRotation(Vector3.up, feetOutHit.normal) * transform.rotation;
return;;
}
feetIkPositions = Vector3.zero;//it didnt work
}
Thank you!