Search Unity

Question I can't seem to get my head around Feet IK

Discussion in 'Scripting' started by JustKrancy, Apr 13, 2021.

  1. JustKrancy

    JustKrancy

    Joined:
    Jul 29, 2019
    Posts:
    3
    I'm controlling my character with a CharacterController.
    I found this code which looks great but isn't doing anything to my feet position, I know the IK is working because when I turn it off and on the knees change, but they aren't being told where to go.
    I'm using unity 2020.3.1f1 if that means anything.

    I'd appreciate any help, thanks!

    edit: I should mention my movement script is different, I'm only using the feet ik section.

    Code (CSharp):
    1. //Copyright Filmstorm (C) 2018-2021 - Movement Controller for Root Motion and built in IK solver
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. //This script requires you to have setup your animator with 3 parameters, "InputMagnitude", "InputX", "InputZ"
    7. //With a blend tree to control the inputmagnitude and allow blending between animations.
    8. [RequireComponent(typeof(CharacterController))]
    9. public class MovementInput : MonoBehaviour
    10. {
    11.     #region Variables
    12.     private float InputX; //Left and Right Inputs
    13.     private float InputZ; //Forward and Back Inputs
    14.     private Vector3 desiredMoveDirection; //Vector that holds desired Move Direction
    15.     private bool blockRotationPlayer = false; //Block the rotation of the player?
    16.     [Range(0,0.5f)] public float desiredRotationSpeed = 0.1f; //Speed of the players rotation
    17.     public Animator anim; //Animator
    18.     private float Speed; //Speed player is moving
    19.     [Range(0,1f)] public float allowPlayerRotation = 0.1f; //Allow player rotation from inputs once past x
    20.     public Camera cam; //Main camera (make sure tag is MainCamera)
    21.     public CharacterController controller; //Character Controller, auto added on script addition
    22.     private bool isGrounded; //is Grounded - work in progress
    23.  
    24.     private Vector3 rightFootPosition, leftFootPosition, leftFootIkPosition, rightFootIkPosition;
    25.     private Quaternion leftFootIkRotation, rightFootIkRotation;
    26.     private float lastPelvisPositionY, lastRightFootPositionY, lastLeftFootPositionY;
    27.  
    28.     [Header("Feet Grounder")]
    29.     public bool enableFeetIk = true;
    30.     [Range(0, 2)] [SerializeField] private float heightFromGroundRaycast = 1.14f;
    31.     [Range(0, 2)] [SerializeField] private float raycastDownDistance = 1.5f;
    32.     [SerializeField] private LayerMask environmentLayer;
    33.     [SerializeField] private float pelvisOffset = 0f;
    34.     [Range(0, 1)] [SerializeField] private float pelvisUpAndDownSpeed = 0.28f;
    35.     [Range(0, 1)] [SerializeField] private float feetToIkPositionSpeed = 0.5f;
    36.  
    37.     public string leftFootAnimVariableName = "LeftFootCurve";
    38.     public string rightFootAnimVariableName = "RightFootCurve";
    39.  
    40.     public bool useProIkFeature = false;
    41.     public bool showSolverDebug = true;
    42.  
    43.  
    44.  
    45.     [Header("Animation Smoothing")]
    46.     [Range(0, 1f)]
    47.     public float HorizontalAnimSmoothTime = 0.2f; //InputX dampening
    48.     [Range(0, 1f)]
    49.     public float VerticalAnimTime = 0.2f; //InputZ dampening
    50.     [Range(0, 1f)]
    51.     public float StartAnimTime = 0.3f; //dampens the time of starting the player after input is pressed
    52.     [Range(0, 1f)]
    53.     public float StopAnimTime = 0.15f; //dampens the time of stopping the player after release of input
    54.  
    55.  
    56.     private float verticalVel; //Vertical velocity -- currently work in progress
    57.     private Vector3 moveVector; //movement vector -- currently work in progress
    58.  
    59.     #endregion
    60.  
    61.     #region Initialization
    62.     // Initialization of variables
    63.     void Start()
    64.     {
    65.         anim = this.GetComponent<Animator>();
    66.         cam = Camera.main;
    67.         controller = this.GetComponent<CharacterController>();
    68.  
    69.         if (anim == null)
    70.             Debug.LogError("We require " + transform.name + " game object to have an animator. This will allow for Foot IK to function");
    71.     }
    72.  
    73.  
    74.     // Update is called once per frame
    75.     void Update()
    76.     {
    77.         InputMagnitude();
    78.      
    79.     }
    80.  
    81.     #endregion
    82.  
    83.  
    84.     #region PlayerMovement
    85.  
    86.     void PlayerMoveAndRotation()
    87.     {
    88.         InputX = Input.GetAxis("Horizontal");
    89.         InputZ = Input.GetAxis("Vertical");
    90.  
    91.         var camera = Camera.main;
    92.         var forward = cam.transform.forward;
    93.         var right = cam.transform.right;
    94.  
    95.         forward.y = 0f;
    96.         right.y = 0f;
    97.  
    98.         forward.Normalize();
    99.         right.Normalize();
    100.  
    101.         desiredMoveDirection = forward * InputZ + right * InputX;
    102.  
    103.         if (blockRotationPlayer == false)
    104.         {
    105.             transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(desiredMoveDirection), desiredRotationSpeed);
    106.         }
    107.     }
    108.  
    109.     void InputMagnitude()
    110.     {
    111.         //Calculate Input Vectors
    112.         InputX = Input.GetAxis("Horizontal");
    113.         InputZ = Input.GetAxis("Vertical");
    114.  
    115.         anim.SetFloat("InputZ", InputZ, VerticalAnimTime, Time.deltaTime * 2f);
    116.         anim.SetFloat("InputX", InputX, HorizontalAnimSmoothTime, Time.deltaTime * 2f);
    117.  
    118.         //Calculate the Input Magnitude
    119.         Speed = new Vector2(InputX, InputZ).sqrMagnitude;
    120.  
    121.         //Physically move player
    122.         if (Speed > allowPlayerRotation)
    123.         {
    124.             anim.SetFloat("InputMagnitude", Speed, StartAnimTime, Time.deltaTime);
    125.             PlayerMoveAndRotation();
    126.         }
    127.         else if (Speed < allowPlayerRotation)
    128.         {
    129.             anim.SetFloat("InputMagnitude", Speed, StopAnimTime, Time.deltaTime);
    130.         }
    131.     }
    132.  
    133.     #endregion
    134.  
    135.  
    136.     #region FeetGrounding
    137.  
    138.     /// <summary>
    139.     /// We are updating the AdjustFeetTarget method and also find the position of each foot inside our Solver Position.
    140.     /// </summary>
    141.     private void FixedUpdate()
    142.     {
    143.         if(enableFeetIk == false) { return; }
    144.         if(anim == null) { return; }
    145.  
    146.         AdjustFeetTarget(ref rightFootPosition, HumanBodyBones.RightFoot);
    147.         AdjustFeetTarget(ref leftFootPosition, HumanBodyBones.LeftFoot);
    148.  
    149.         //find and raycast to the ground to find positions
    150.         FeetPositionSolver(rightFootPosition, ref rightFootIkPosition, ref rightFootIkRotation); // handle the solver for right foot
    151.         FeetPositionSolver(leftFootPosition, ref leftFootIkPosition, ref leftFootIkRotation); //handle the solver for the left foot
    152.  
    153.     }
    154.  
    155.     private void OnAnimatorIK(int layerIndex)
    156.     {
    157.         if(enableFeetIk == false) { return; }
    158.         if(anim == null) { return; }
    159.  
    160.         MovePelvisHeight();
    161.  
    162.         //right foot ik position and rotation -- utilise the pro features in here
    163.         anim.SetIKPositionWeight(AvatarIKGoal.RightFoot, 1);
    164.  
    165.         if(useProIkFeature)
    166.         {
    167.             anim.SetIKRotationWeight(AvatarIKGoal.RightFoot, anim.GetFloat(rightFootAnimVariableName));
    168.         }
    169.  
    170.         MoveFeetToIkPoint(AvatarIKGoal.RightFoot, rightFootIkPosition, rightFootIkRotation, ref lastRightFootPositionY);
    171.  
    172.         //left foot ik position and rotation -- utilise the pro features in here
    173.         anim.SetIKPositionWeight(AvatarIKGoal.LeftFoot, 1);
    174.  
    175.         if (useProIkFeature)
    176.         {
    177.             anim.SetIKRotationWeight(AvatarIKGoal.LeftFoot, anim.GetFloat(leftFootAnimVariableName));
    178.         }
    179.  
    180.         MoveFeetToIkPoint(AvatarIKGoal.LeftFoot, leftFootIkPosition, leftFootIkRotation, ref lastLeftFootPositionY);
    181.     }
    182.  
    183.     #endregion
    184.  
    185.  
    186.  
    187.     #region FeetGroundingMethods
    188.  
    189.     /// <summary>
    190.     /// Moves the feet to ik point.
    191.     /// </summary>
    192.     /// <param name="foot">Foot.</param>
    193.     /// <param name="positionIkHolder">Position ik holder.</param>
    194.     /// <param name="rotationIkHolder">Rotation ik holder.</param>
    195.     /// <param name="lastFootPositionY">Last foot position y.</param>
    196.     void MoveFeetToIkPoint (AvatarIKGoal foot, Vector3 positionIkHolder, Quaternion rotationIkHolder, ref float lastFootPositionY)
    197.     {
    198.         Vector3 targetIkPosition = anim.GetIKPosition(foot);
    199.  
    200.         if(positionIkHolder != Vector3.zero)
    201.         {
    202.             targetIkPosition = transform.InverseTransformPoint(targetIkPosition);
    203.             positionIkHolder = transform.InverseTransformPoint(positionIkHolder);
    204.  
    205.             float yVariable = Mathf.Lerp(lastFootPositionY, positionIkHolder.y, feetToIkPositionSpeed);
    206.             targetIkPosition.y += yVariable;
    207.  
    208.             lastFootPositionY = yVariable;
    209.  
    210.             targetIkPosition = transform.TransformPoint(targetIkPosition);
    211.  
    212.             anim.SetIKRotation(foot, rotationIkHolder);
    213.         }
    214.  
    215.         anim.SetIKPosition(foot, targetIkPosition);
    216.     }
    217.     /// <summary>
    218.     /// Moves the height of the pelvis.
    219.     /// </summary>
    220.     private void MovePelvisHeight()
    221.     {
    222.  
    223.         if(rightFootIkPosition == Vector3.zero || leftFootIkPosition == Vector3.zero || lastPelvisPositionY == 0)
    224.         {
    225.             lastPelvisPositionY = anim.bodyPosition.y;
    226.             return;
    227.         }
    228.  
    229.         float lOffsetPosition = leftFootIkPosition.y - transform.position.y;
    230.         float rOffsetPosition = rightFootIkPosition.y - transform.position.y;
    231.  
    232.         float totalOffset = (lOffsetPosition < rOffsetPosition) ? lOffsetPosition : rOffsetPosition;
    233.  
    234.         Vector3 newPelvisPosition = anim.bodyPosition + Vector3.up * totalOffset;
    235.  
    236.         newPelvisPosition.y = Mathf.Lerp(lastPelvisPositionY, newPelvisPosition.y, pelvisUpAndDownSpeed);
    237.  
    238.         anim.bodyPosition = newPelvisPosition;
    239.  
    240.         lastPelvisPositionY = anim.bodyPosition.y;
    241.  
    242.     }
    243.  
    244.     /// <summary>
    245.     /// We are locating the Feet position via a Raycast and then Solving
    246.     /// </summary>
    247.     /// <param name="fromSkyPosition">From sky position.</param>
    248.     /// <param name="feetIkPositions">Feet ik positions.</param>
    249.     /// <param name="feetIkRotations">Feet ik rotations.</param>
    250.     private void FeetPositionSolver(Vector3 fromSkyPosition, ref Vector3 feetIkPositions, ref Quaternion feetIkRotations)
    251.     {
    252.         //raycast handling section
    253.         RaycastHit feetOutHit;
    254.  
    255.         if (showSolverDebug)
    256.             Debug.DrawLine(fromSkyPosition, fromSkyPosition + Vector3.down * (raycastDownDistance + heightFromGroundRaycast), Color.yellow);
    257.  
    258.         if (Physics.Raycast(fromSkyPosition, Vector3.down, out feetOutHit, raycastDownDistance + heightFromGroundRaycast, environmentLayer))
    259.         {
    260.             //finding our feet ik positions from the sky position
    261.             feetIkPositions = fromSkyPosition;
    262.             feetIkPositions.y = feetOutHit.point.y + pelvisOffset;
    263.             feetIkRotations = Quaternion.FromToRotation(Vector3.up, feetOutHit.normal) * transform.rotation;
    264.  
    265.             return;
    266.         }
    267.  
    268.         feetIkPositions = Vector3.zero; //it didn't work :(
    269.  
    270.     }
    271.     /// <summary>
    272.     /// Adjusts the feet target.
    273.     /// </summary>
    274.     /// <param name="feetPositions">Feet positions.</param>
    275.     /// <param name="foot">Foot.</param>
    276.     private void AdjustFeetTarget (ref Vector3 feetPositions, HumanBodyBones foot)
    277.     {
    278.         feetPositions = anim.GetBoneTransform(foot).position;
    279.         feetPositions.y = transform.position.y + heightFromGroundRaycast;
    280.  
    281.     }
    282.  
    283.     #endregion
    284.  
    285.  
    286. }
    287.