123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- using UnityEngine;
- using System.Collections;
- using RootMotion.FinalIK;
- namespace RootMotion.Demos {
- // Extends the default Animator controller for 3rd person view to add IK
- public class AnimatorController3rdPersonIK: AnimatorController3rdPerson {
- [Range(0f, 1f)] public float headLookWeight = 1f;
- public Vector3 gunHoldOffset;
- public Vector3 leftHandOffset;
- public Recoil recoil;
- // The IK components
- private AimIK aim;
- private FullBodyBipedIK ik;
- private Vector3 headLookAxis;
- private Vector3 leftHandPosRelToRightHand;
- private Quaternion leftHandRotRelToRightHand;
- private Vector3 aimTarget;
- private Quaternion rightHandRotation;
- protected override void Start() {
- base.Start();
-
- // Find the IK components
- aim = GetComponent<AimIK>();
- ik = GetComponent<FullBodyBipedIK>();
- ik.solver.OnPreRead += OnPreRead;
-
- // Disable the IK components to manage their updating
- aim.enabled = false;
- ik.enabled = false;
- // Presuming head is rotated towards character forward at Start
- headLookAxis = ik.references.head.InverseTransformVector(ik.references.root.forward);
-
- // Enable the upper-body aiming pose
- animator.SetLayerWeight(1, 1f);
- }
- public override void Move(Vector3 moveInput, bool isMoving, Vector3 faceDirection, Vector3 aimTarget) {
- base.Move(moveInput, isMoving, faceDirection, aimTarget);
- // Snatch the aim target from the Move call, it will be used by AimIK (Move is called by CharacterController3rdPerson that controls the actual motion of the character)
- this.aimTarget = aimTarget;
- // IK procedures, make sure this updates AFTER the camera is moved/rotated
- // Sample something from the current pose of the character
- Read();
- // AimIK pass
- AimIK();
- // FBBIK pass - put the left hand back to where it was relative to the right hand before AimIK solved
- FBBIK();
- // AimIK pass
- AimIK();
- // Rotate the head to look at the aim target
- HeadLookAt(aimTarget);
- }
- private void Read() {
- // Remember the position and rotation of the left hand relative to the right hand
- leftHandPosRelToRightHand = ik.references.rightHand.InverseTransformPoint(ik.references.leftHand.position);
- leftHandRotRelToRightHand = Quaternion.Inverse(ik.references.rightHand.rotation) * ik.references.leftHand.rotation;
- }
- private void AimIK() {
- // Set AimIK target position and update
- aim.solver.IKPosition = aimTarget;
- aim.solver.Update(); // Update AimIK
- }
- // Positioning the left hand on the gun after aiming has finished
- private void FBBIK() {
- // Store the current rotation of the right hand
- rightHandRotation = ik.references.rightHand.rotation;
- // Offsetting hands, you might need that to support multiple weapons with the same aiming pose
- Vector3 rightHandOffset = ik.references.rightHand.rotation * gunHoldOffset;
- ik.solver.rightHandEffector.positionOffset += rightHandOffset;
- if (recoil != null) recoil.SetHandRotations(rightHandRotation * leftHandRotRelToRightHand, rightHandRotation);
- // Update FBBIK
- ik.solver.Update();
-
- // Rotating the hand bones after IK has finished
- if (recoil != null) {
- ik.references.rightHand.rotation = recoil.rotationOffset * rightHandRotation;
- ik.references.leftHand.rotation = recoil.rotationOffset * rightHandRotation * leftHandRotRelToRightHand;
- } else {
- ik.references.rightHand.rotation = rightHandRotation;
- ik.references.leftHand.rotation = rightHandRotation * leftHandRotRelToRightHand;
- }
- }
- // Final calculations before FBBIK solves. Recoil has already solved by, so we can use it's calculated offsets.
- // Here we set the left hand position relative to the position and rotation of the right hand.
- private void OnPreRead() {
- Quaternion r = recoil != null? recoil.rotationOffset * rightHandRotation: rightHandRotation;
- Vector3 leftHandTarget = ik.references.rightHand.position + ik.solver.rightHandEffector.positionOffset + r * leftHandPosRelToRightHand;
- ik.solver.leftHandEffector.positionOffset += leftHandTarget - ik.references.leftHand.position - ik.solver.leftHandEffector.positionOffset + r * leftHandOffset;
- }
- // Rotating the head to look at the target
- private void HeadLookAt(Vector3 lookAtTarget) {
- Quaternion headRotationTarget = Quaternion.FromToRotation(ik.references.head.rotation * headLookAxis, lookAtTarget - ik.references.head.position);
- ik.references.head.rotation = Quaternion.Lerp(Quaternion.identity, headRotationTarget, headLookWeight) * ik.references.head.rotation;
- }
- // Cleaning up the delegates
- void OnDestroy() {
- if (ik != null) ik.solver.OnPreRead -= OnPreRead;
- }
- }
- }
|