Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- namespace AGD.Core.IK
- {
- /// <summary>
- /// To be placed on a character in order to add a foot IK grounding behaviour
- /// Requires an Animator with a Layer set to IK Pass
- /// </summary>
- [RequireComponent(typeof(Animator))]
- public class FootIK : MonoBehaviour
- {
- [Tooltip("Set to false and this script won't run.")]
- [SerializeField] private bool applyFootIK = true;
- [Tooltip("Select the layer to which the foot IK will be applied")]
- [SerializeField] private LayerMask targetLayer;
- [Tooltip("the distance of the ray check from the IK Foot Transform towards the ground")]
- [Range(0,1)][SerializeField] private float checkDistance = 0;
- [Tooltip("the offset from the IK Foot Transform to the lowest point of the foot")]
- [Range(0,1)][SerializeField] private float feetOffset = 0;
- private Animator _animator;
- private Collider _collider;
- private void Start()
- {
- _animator = GetComponent<Animator>();
- _collider = GetComponent<Collider>();
- }
- private void OnAnimatorIK(int layerIndex)
- {
- if (!applyFootIK) return;
- if (!_animator) return;
- // Set the weights of feet IK to the current value defined by the curve in the animations.
- _animator.SetIKPositionWeight(AvatarIKGoal.LeftFoot, _animator.GetFloat("IKLeftFootWeight"));
- _animator.SetIKRotationWeight(AvatarIKGoal.LeftFoot, _animator.GetFloat("IKLeftFootWeight"));
- _animator.SetIKPositionWeight(AvatarIKGoal.RightFoot, _animator.GetFloat("IKRightFootWeight"));
- _animator.SetIKRotationWeight(AvatarIKGoal.RightFoot, _animator.GetFloat("IKRightFootWeight"));
- //Variables used to calculated pelvis position after calculating the feet position
- var leftFootYOffset = 0f;
- var rightFootYOffset = 0f;
- //Setting IK Positions
- //Left Foot
- RaycastHit hitInfo_1;
- RaycastHit hitInfo_2;
- //a ray starting from the center of the collider and going downward on the Y Axis
- Ray ray_1 = new Ray(_animator.GetIKPosition(AvatarIKGoal.LeftFoot) + new Vector3(0,_collider.bounds.extents.y,0), Vector3.down);
- Ray ray_2 = new Ray(_animator.GetIKPosition(AvatarIKGoal.LeftFoot) + new Vector3(0,_collider.bounds.extents.y,.15f), Vector3.down);
- Debug.DrawRay(_animator.GetIKPosition(AvatarIKGoal.LeftFoot) + new Vector3(0,_collider.bounds.extents.y,0),
- Vector3.down * (_collider.bounds.extents.y + checkDistance), Color.red);
- Debug.DrawRay(_animator.GetIKPosition(AvatarIKGoal.LeftFoot) + new Vector3(0,_collider.bounds.extents.y,.15f),
- Vector3.down * (_collider.bounds.extents.y + checkDistance / 2), Color.red);
- if (Physics.Raycast(ray_1, out hitInfo_1, _collider.bounds.extents.y + checkDistance,
- targetLayer))
- {
- //the length of the offset between the current foot position and it's target position
- leftFootYOffset = (hitInfo_1.point - _animator.GetIKPosition(AvatarIKGoal.LeftFoot)).magnitude;
- var footPosition = hitInfo_1.point; //The point in space where the ray hit the targetLayer ie: where the foot should be placed.
- footPosition.y += feetOffset; //lifting the foot back up to compensate for the feet Offset.
- _animator.SetIKPosition(AvatarIKGoal.LeftFoot, footPosition);
- //Rotating the foot in a direction so that Vector3.up's rotation matches the hit surface's normal rotation.
- _animator.SetIKRotation(AvatarIKGoal.LeftFoot, Quaternion.FromToRotation(Vector3.up, hitInfo_1.normal));
- }
- else if (Physics.Raycast(ray_2, out hitInfo_2, _collider.bounds.extents.y + checkDistance / 2,
- targetLayer))
- {
- //the length of the offset between the current foot position and it's target position
- leftFootYOffset = (hitInfo_2.point - new Vector3(0,0,.15f) - _animator.GetIKPosition(AvatarIKGoal.LeftFoot)).magnitude;
- var footPosition = hitInfo_2.point - new Vector3(0,0,.15f); // same logic as above but with an offset that is the foot-toes distance.
- footPosition.y += feetOffset; //lifting the foot back up to compensate for the feet Offset.
- _animator.SetIKPosition(AvatarIKGoal.LeftFoot, footPosition);
- //Rotating the foot in a direction so that Vector3.up's rotation matches the hit surface's normal rotation.
- _animator.SetIKRotation(AvatarIKGoal.LeftFoot, Quaternion.FromToRotation(Vector3.up, hitInfo_2.normal));
- }
- //Right Foot
- //a ray starting from the center of the collider and going downward on the Y Axis
- ray_1 = new Ray(_animator.GetIKPosition(AvatarIKGoal.RightFoot) + new Vector3(0,_collider.bounds.extents.y,0), Vector3.down);
- ray_2 = new Ray(_animator.GetIKPosition(AvatarIKGoal.RightFoot) + new Vector3(0,_collider.bounds.extents.y,.15f), Vector3.down);
- Debug.DrawRay(_animator.GetIKPosition(AvatarIKGoal.RightFoot) + new Vector3(0,_collider.bounds.extents.y,0),
- Vector3.down * (_collider.bounds.extents.y + checkDistance), Color.red);
- Debug.DrawRay(_animator.GetIKPosition(AvatarIKGoal.RightFoot) + new Vector3(0,_collider.bounds.extents.y,.15f),
- Vector3.down * (_collider.bounds.extents.y + checkDistance / 2), Color.red);
- if (Physics.Raycast(ray_1, out hitInfo_1, _collider.bounds.extents.y + checkDistance,
- targetLayer))
- {
- //the length of the offset between the current foot position and it's target position
- rightFootYOffset = (hitInfo_1.point - _animator.GetIKPosition(AvatarIKGoal.RightFoot)).magnitude;
- var footPosition = hitInfo_1.point; //The point in space where the ray hit the targetLayer ie: where the foot should be placed.
- footPosition.y += feetOffset; //lifting the foot back up to compensate for the feet Offset.
- _animator.SetIKPosition(AvatarIKGoal.RightFoot, footPosition);
- //Rotating the foot in a direction so that Vector3.up's rotation matches the hit surface's normal rotation.
- _animator.SetIKRotation(AvatarIKGoal.RightFoot, Quaternion.FromToRotation(Vector3.up, hitInfo_1.normal));
- }
- else if (Physics.Raycast(ray_2, out hitInfo_2, _collider.bounds.extents.y + checkDistance / 2,
- targetLayer))
- {
- //the length of the offset between the current foot position and it's target position
- rightFootYOffset = (hitInfo_2.point - new Vector3(0,0,.15f) - _animator.GetIKPosition(AvatarIKGoal.RightFoot)).magnitude;
- var footPosition = hitInfo_2.point - new Vector3(0,0,.15f); // same logic as above but with an offset that is the foot-toes distance.
- footPosition.y += feetOffset; //lifting the foot back up to compensate for the feet Offset.
- _animator.SetIKPosition(AvatarIKGoal.RightFoot, footPosition);
- //Rotating the foot in a direction so that Vector3.up's rotation matches the hit surface's normal rotation.
- _animator.SetIKRotation(AvatarIKGoal.RightFoot, Quaternion.FromToRotation(Vector3.up, hitInfo_2.normal));
- }
- //Pelvis
- var pelvisYOffset = Mathf.Max(leftFootYOffset, rightFootYOffset);
- var pelvisOffset = new Vector3(0,pelvisYOffset,0);
- _animator.bodyPosition -= pelvisOffset * _animator.GetFloat("IKPelvisWeight");
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement