Feet IK Rotation problem

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!

I’ve managed to sort this out eventually. Bought some IK assets and looked at their code for the proper rotation function and implemented it into mine.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms