You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			463 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C#
		
	
		
		
			
		
	
	
			463 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C#
		
	
| 
								 
											1 year ago
										 
									 | 
							
								using UnityEngine;
							 | 
						||
| 
								 | 
							
								using System.Collections;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace RootMotion.FinalIK {
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/// <summary>
							 | 
						||
| 
								 | 
							
									/// Rotates a hierarchy of bones to face a target.
							 | 
						||
| 
								 | 
							
									/// </summary>
							 | 
						||
| 
								 | 
							
									[System.Serializable]
							 | 
						||
| 
								 | 
							
									public class IKSolverLookAt : IKSolver {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										#region Main Interface
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// The target Transform.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										public Transform target;
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// The spine hierarchy.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										public LookAtBone[] spine = new LookAtBone[0];
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// The head bone.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										public LookAtBone head = new LookAtBone();
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// The eye bones.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										public LookAtBone[] eyes = new LookAtBone[0];
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// The body weight.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										[Range(0f, 1f)]
							 | 
						||
| 
								 | 
							
										public float bodyWeight = 0.5f;
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// The head weight.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										[Range(0f, 1f)]
							 | 
						||
| 
								 | 
							
										public float headWeight = 0.5f;
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// The eyes weight.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										[Range(0f, 1f)]
							 | 
						||
| 
								 | 
							
										public float eyesWeight = 1f;
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// Clamp weight for the body.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										[Range(0f, 1f)]
							 | 
						||
| 
								 | 
							
										public float clampWeight = 0.5f;
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// Clamp weight for the head.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										[Range(0f, 1f)]
							 | 
						||
| 
								 | 
							
										public float clampWeightHead = 0.5f;
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// Clamp weight for the eyes.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										[Range(0f, 1f)]
							 | 
						||
| 
								 | 
							
										public float clampWeightEyes = 0.5f;
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// Number of sine smoothing iterations applied on clamping to make the clamping point smoother.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										[Range(0, 2)]
							 | 
						||
| 
								 | 
							
										public int clampSmoothing = 2;
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// Weight distribution between the spine bones.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										public AnimationCurve spineWeightCurve = new AnimationCurve(new Keyframe[2] { new Keyframe(0f, 0.3f), new Keyframe(1f, 1f) });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// Offset for the spine target in world space..
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										public Vector3 spineTargetOffset;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// Sets the look at weight. NOTE: You are welcome edit the weights directly, this method is here only to match the Unity's built in %IK API.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										public void SetLookAtWeight(float weight) {
							 | 
						||
| 
								 | 
							
											this.IKPositionWeight = Mathf.Clamp(weight, 0f, 1f);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// Sets the look at weight. NOTE: You are welcome to edit the weights directly, this method is here only to match the Unity's built in %IK API.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										public void SetLookAtWeight(float weight, float bodyWeight) {
							 | 
						||
| 
								 | 
							
											this.IKPositionWeight = Mathf.Clamp(weight, 0f, 1f);
							 | 
						||
| 
								 | 
							
											this.bodyWeight = Mathf.Clamp(bodyWeight, 0f, 1f);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// Sets the look at weight. NOTE: You are welcome to edit the weights directly, this method is here only to match the Unity's built in %IK API.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										public void SetLookAtWeight(float weight, float bodyWeight, float headWeight) {
							 | 
						||
| 
								 | 
							
											this.IKPositionWeight = Mathf.Clamp(weight, 0f, 1f);
							 | 
						||
| 
								 | 
							
											this.bodyWeight = Mathf.Clamp(bodyWeight, 0f, 1f);
							 | 
						||
| 
								 | 
							
											this.headWeight = Mathf.Clamp(headWeight, 0f, 1f);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// Sets the look at weight. NOTE: You are welcome to edit the weights directly, this method is here only to match the Unity's built in %IK API.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										public void SetLookAtWeight(float weight, float bodyWeight, float headWeight, float eyesWeight) {
							 | 
						||
| 
								 | 
							
											this.IKPositionWeight = Mathf.Clamp(weight, 0f, 1f);
							 | 
						||
| 
								 | 
							
											this.bodyWeight = Mathf.Clamp(bodyWeight, 0f, 1f);
							 | 
						||
| 
								 | 
							
											this.headWeight = Mathf.Clamp(headWeight, 0f, 1f);
							 | 
						||
| 
								 | 
							
											this.eyesWeight = Mathf.Clamp(eyesWeight, 0f, 1f);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// Sets the look at weight. NOTE: You are welcome to edit the weights directly, this method is here only to match the Unity's built in %IK API. 
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										public void SetLookAtWeight(float weight, float bodyWeight, float headWeight, float eyesWeight, float clampWeight) {
							 | 
						||
| 
								 | 
							
											this.IKPositionWeight = Mathf.Clamp(weight, 0f, 1f);
							 | 
						||
| 
								 | 
							
											this.bodyWeight = Mathf.Clamp(bodyWeight, 0f, 1f);
							 | 
						||
| 
								 | 
							
											this.headWeight = Mathf.Clamp(headWeight, 0f, 1f);
							 | 
						||
| 
								 | 
							
											this.eyesWeight = Mathf.Clamp(eyesWeight, 0f, 1f);
							 | 
						||
| 
								 | 
							
											this.clampWeight = Mathf.Clamp(clampWeight, 0f, 1f);
							 | 
						||
| 
								 | 
							
											this.clampWeightHead = this.clampWeight;
							 | 
						||
| 
								 | 
							
											this.clampWeightEyes = this.clampWeight;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// Sets the look at weight. NOTE: You are welcome to edit the weights directly, this method is here only to match the Unity's built in %IK API.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										public void SetLookAtWeight(float weight, float bodyWeight = 0f, float headWeight = 1f, float eyesWeight = 0.5f, float clampWeight = 0.5f, float clampWeightHead = 0.5f, float clampWeightEyes = 0.3f) {
							 | 
						||
| 
								 | 
							
											this.IKPositionWeight = Mathf.Clamp(weight, 0f, 1f);
							 | 
						||
| 
								 | 
							
											this.bodyWeight = Mathf.Clamp(bodyWeight, 0f, 1f);
							 | 
						||
| 
								 | 
							
											this.headWeight = Mathf.Clamp(headWeight, 0f, 1f);
							 | 
						||
| 
								 | 
							
											this.eyesWeight = Mathf.Clamp(eyesWeight, 0f, 1f);
							 | 
						||
| 
								 | 
							
											this.clampWeight = Mathf.Clamp(clampWeight, 0f, 1f);
							 | 
						||
| 
								 | 
							
											this.clampWeightHead = Mathf.Clamp(clampWeightHead, 0f, 1f);
							 | 
						||
| 
								 | 
							
											this.clampWeightEyes = Mathf.Clamp(clampWeightEyes, 0f, 1f);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										public override void StoreDefaultLocalState() {
							 | 
						||
| 
								 | 
							
											for (int i = 0; i < spine.Length; i++) spine[i].StoreDefaultLocalState();
							 | 
						||
| 
								 | 
							
											for (int i = 0; i < eyes.Length; i++) eyes[i].StoreDefaultLocalState();
							 | 
						||
| 
								 | 
							
											if (head != null && head.transform != null) head.StoreDefaultLocalState();
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Flag for Fix Transforms.
							 | 
						||
| 
								 | 
							
								        public void SetDirty()
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            isDirty = true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public override void FixTransforms() {
							 | 
						||
| 
								 | 
							
											if (!initiated) return;
							 | 
						||
| 
								 | 
							
											if (IKPositionWeight <= 0f && !isDirty) return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											for (int i = 0; i < spine.Length; i++) spine[i].FixTransform();
							 | 
						||
| 
								 | 
							
											for (int i = 0; i < eyes.Length; i++) eyes[i].FixTransform();
							 | 
						||
| 
								 | 
							
											if (head != null && head.transform != null) head.FixTransform();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            isDirty = false;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										public override bool IsValid (ref string message) {
							 | 
						||
| 
								 | 
							
											if (!spineIsValid) {
							 | 
						||
| 
								 | 
							
												message = "IKSolverLookAt spine setup is invalid. Can't initiate solver.";
							 | 
						||
| 
								 | 
							
												return false;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											if (!headIsValid) {
							 | 
						||
| 
								 | 
							
												message = "IKSolverLookAt head transform is null. Can't initiate solver.";
							 | 
						||
| 
								 | 
							
												return false;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											if (!eyesIsValid) {
							 | 
						||
| 
								 | 
							
												message = "IKSolverLookAt eyes setup is invalid. Can't initiate solver.";
							 | 
						||
| 
								 | 
							
												return false;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if (spineIsEmpty && headIsEmpty && eyesIsEmpty) {
							 | 
						||
| 
								 | 
							
												message = "IKSolverLookAt eyes setup is invalid. Can't initiate solver.";
							 | 
						||
| 
								 | 
							
												return false;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											Transform spineDuplicate = ContainsDuplicateBone(spine);
							 | 
						||
| 
								 | 
							
											if (spineDuplicate != null) {
							 | 
						||
| 
								 | 
							
												message = spineDuplicate.name + " is represented multiple times in a single IK chain. Can't initiate solver.";
							 | 
						||
| 
								 | 
							
												return false;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											Transform eyeDuplicate = ContainsDuplicateBone(eyes);
							 | 
						||
| 
								 | 
							
											if (eyeDuplicate != null) {
							 | 
						||
| 
								 | 
							
												message = eyeDuplicate.name + " is represented multiple times in a single IK chain. Can't initiate solver.";
							 | 
						||
| 
								 | 
							
												return false;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											return true;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										public override IKSolver.Point[] GetPoints() {
							 | 
						||
| 
								 | 
							
											IKSolver.Point[] allPoints = new IKSolver.Point[spine.Length + eyes.Length + (head.transform != null? 1: 0)];
							 | 
						||
| 
								 | 
							
											for (int i = 0; i < spine.Length; i++) allPoints[i] = spine[i] as IKSolver.Point;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            int eye = 0;
							 | 
						||
| 
								 | 
							
								            for (int i = spine.Length; i < spine.Length + eyes.Length; i++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                allPoints[i] = eyes[eye] as IKSolver.Point;
							 | 
						||
| 
								 | 
							
								                eye++;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											if (head.transform != null) allPoints[allPoints.Length - 1] = head as IKSolver.Point;
							 | 
						||
| 
								 | 
							
											return allPoints;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										public override IKSolver.Point GetPoint(Transform transform) {
							 | 
						||
| 
								 | 
							
											foreach (IKSolverLookAt.LookAtBone b in spine) if (b.transform == transform) return b as IKSolver.Point;
							 | 
						||
| 
								 | 
							
											foreach (IKSolverLookAt.LookAtBone b in eyes) if (b.transform == transform) return b as IKSolver.Point;
							 | 
						||
| 
								 | 
							
											if (head.transform == transform) return head as IKSolver.Point;
							 | 
						||
| 
								 | 
							
											return null;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// Look At bone class.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										[System.Serializable]
							 | 
						||
| 
								 | 
							
										public class LookAtBone: IKSolver.Bone {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            #region Public methods
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            public Vector3 baseForwardOffsetEuler;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											public LookAtBone() {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											/*
							 | 
						||
| 
								 | 
							
											 * Custom constructor
							 | 
						||
| 
								 | 
							
											 * */
							 | 
						||
| 
								 | 
							
											public LookAtBone(Transform transform) {
							 | 
						||
| 
								 | 
							
												this.transform = transform;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											/*
							 | 
						||
| 
								 | 
							
											 * Initiates the bone, precalculates values.
							 | 
						||
| 
								 | 
							
											 * */
							 | 
						||
| 
								 | 
							
											public void Initiate(Transform root) {
							 | 
						||
| 
								 | 
							
												if (transform == null) return;
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
												axis = Quaternion.Inverse(transform.rotation) * root.forward;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											/*
							 | 
						||
| 
								 | 
							
											 * Rotates the bone to look at a world direction.
							 | 
						||
| 
								 | 
							
											 * */
							 | 
						||
| 
								 | 
							
											public void LookAt(Vector3 direction, float weight) {
							 | 
						||
| 
								 | 
							
												Quaternion fromTo = Quaternion.FromToRotation(forward, direction);
							 | 
						||
| 
								 | 
							
												Quaternion r = transform.rotation;
							 | 
						||
| 
								 | 
							
												transform.rotation = Quaternion.Lerp(r, fromTo * r, weight);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											/*
							 | 
						||
| 
								 | 
							
											 * Gets the local axis to goal in world space.
							 | 
						||
| 
								 | 
							
											 * */
							 | 
						||
| 
								 | 
							
											public Vector3 forward {
							 | 
						||
| 
								 | 
							
												get {
							 | 
						||
| 
								 | 
							
													return transform.rotation * axis;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											#endregion Public methods
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										/// <summary>
							 | 
						||
| 
								 | 
							
										/// Reinitiate the solver with new bone Transforms.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
										/// <returns>
							 | 
						||
| 
								 | 
							
										/// Returns true if the new chain is valid.
							 | 
						||
| 
								 | 
							
										/// </returns>
							 | 
						||
| 
								 | 
							
										public bool SetChain(Transform[] spine, Transform head, Transform[] eyes, Transform root) {
							 | 
						||
| 
								 | 
							
											// Spine
							 | 
						||
| 
								 | 
							
											SetBones(spine, ref this.spine);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Head
							 | 
						||
| 
								 | 
							
											this.head = new LookAtBone(head);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Eyes
							 | 
						||
| 
								 | 
							
											SetBones(eyes, ref this.eyes);
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											Initiate(root);
							 | 
						||
| 
								 | 
							
											return initiated;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										#endregion Main Interface
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										protected Vector3[] spineForwards = new Vector3[0];
							 | 
						||
| 
								 | 
							
								        protected Vector3[] headForwards = new Vector3[1];
							 | 
						||
| 
								 | 
							
								        protected Vector3[] eyeForward = new Vector3[1];
							 | 
						||
| 
								 | 
							
								        private bool isDirty;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        protected override void OnInitiate() {
							 | 
						||
| 
								 | 
							
											// Set IKPosition to default value
							 | 
						||
| 
								 | 
							
											if (firstInitiation || !Application.isPlaying) {
							 | 
						||
| 
								 | 
							
												if (spine.Length > 0) IKPosition = spine[spine.Length - 1].transform.position + root.forward * 3f;
							 | 
						||
| 
								 | 
							
												else if (head.transform != null) IKPosition = head.transform.position + root.forward * 3f;
							 | 
						||
| 
								 | 
							
												else if (eyes.Length > 0 && eyes[0].transform != null) IKPosition = eyes[0].transform.position + root.forward * 3f;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											// Initiating the bones
							 | 
						||
| 
								 | 
							
											foreach (LookAtBone s in spine) s.Initiate(root);
							 | 
						||
| 
								 | 
							
											if (head != null) head.Initiate(root);
							 | 
						||
| 
								 | 
							
											foreach (LookAtBone eye in eyes) eye.Initiate(root);
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											if (spineForwards == null || spineForwards.Length != spine.Length) spineForwards = new Vector3[spine.Length];
							 | 
						||
| 
								 | 
							
											if (headForwards == null) headForwards = new Vector3[1];
							 | 
						||
| 
								 | 
							
											if (eyeForward == null) eyeForward = new Vector3[1];
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										protected override void OnUpdate() {
							 | 
						||
| 
								 | 
							
											if (IKPositionWeight <= 0) return;
							 | 
						||
| 
								 | 
							
											IKPositionWeight = Mathf.Clamp(IKPositionWeight, 0f, 1f);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if (target != null) IKPosition = target.position;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Solving the hierarchies
							 | 
						||
| 
								 | 
							
											SolveSpine();
							 | 
						||
| 
								 | 
							
											SolveHead();
							 | 
						||
| 
								 | 
							
											SolveEyes();
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        protected bool spineIsValid {
							 | 
						||
| 
								 | 
							
											get {
							 | 
						||
| 
								 | 
							
												if (spine == null) return false;
							 | 
						||
| 
								 | 
							
												if (spine.Length == 0) return true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												for (int i = 0; i < spine.Length; i++) if (spine[i] == null || spine[i].transform == null) return false;
							 | 
						||
| 
								 | 
							
												return true;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        protected bool spineIsEmpty { get { return spine.Length == 0; }}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Solving the spine hierarchy
							 | 
						||
| 
								 | 
							
								        protected void SolveSpine() {
							 | 
						||
| 
								 | 
							
											if (bodyWeight <= 0) return;
							 | 
						||
| 
								 | 
							
											if (spineIsEmpty) return;
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											// Get the look at vectors for each bone
							 | 
						||
| 
								 | 
							
											//Vector3 targetForward = Vector3.Lerp(spine[0].forward, (IKPosition - spine[spine.Length - 1].transform.position).normalized, bodyWeight * IKPositionWeight).normalized;
							 | 
						||
| 
								 | 
							
											Vector3 targetForward = (IKPosition + spineTargetOffset - spine[spine.Length - 1].transform.position).normalized;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											GetForwards(ref spineForwards, spine[0].forward, targetForward, spine.Length, clampWeight);
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											// Rotate each bone to face their look at vectors
							 | 
						||
| 
								 | 
							
											for (int i = 0; i < spine.Length; i++) {
							 | 
						||
| 
								 | 
							
												spine[i].LookAt(spineForwards[i], bodyWeight * IKPositionWeight);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        protected bool headIsValid {
							 | 
						||
| 
								 | 
							
											get {
							 | 
						||
| 
								 | 
							
												if (head == null) return false;
							 | 
						||
| 
								 | 
							
												return true;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        protected bool headIsEmpty { get { return head.transform == null; }}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Solving the head rotation
							 | 
						||
| 
								 | 
							
								        protected void SolveHead() {
							 | 
						||
| 
								 | 
							
											if (headWeight <= 0) return;
							 | 
						||
| 
								 | 
							
											if (headIsEmpty) return;
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											// Get the look at vector for the head
							 | 
						||
| 
								 | 
							
											Vector3 baseForward = spine.Length > 0 && spine[spine.Length - 1].transform != null? spine[spine.Length - 1].forward: head.forward;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											Vector3 targetForward = Vector3.Lerp(baseForward, (IKPosition - head.transform.position).normalized, headWeight * IKPositionWeight).normalized;
							 | 
						||
| 
								 | 
							
											GetForwards(ref headForwards, baseForward, targetForward, 1, clampWeightHead);
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											// Rotate the head to face its look at vector
							 | 
						||
| 
								 | 
							
											head.LookAt(headForwards[0], headWeight * IKPositionWeight);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        protected bool eyesIsValid {
							 | 
						||
| 
								 | 
							
											get {
							 | 
						||
| 
								 | 
							
												if (eyes == null) return false;
							 | 
						||
| 
								 | 
							
												if (eyes.Length == 0) return true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												for (int i = 0; i < eyes.Length; i++) if (eyes[i] == null || eyes[i].transform == null) return false;
							 | 
						||
| 
								 | 
							
												return true;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        protected bool eyesIsEmpty { get { return eyes.Length == 0; }}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Solving the eye rotations
							 | 
						||
| 
								 | 
							
								        protected void SolveEyes() {
							 | 
						||
| 
								 | 
							
											if (eyesWeight <= 0) return;
							 | 
						||
| 
								 | 
							
											if (eyesIsEmpty) return;
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											for (int i = 0; i < eyes.Length; i++) {
							 | 
						||
| 
								 | 
							
								                // Get the look at vector for the eye
							 | 
						||
| 
								 | 
							
								                Quaternion baseRotation = head.transform != null ? head.transform.rotation : spine.Length > 0? spine[spine.Length - 1].transform.rotation: root.rotation;
							 | 
						||
| 
								 | 
							
								                Vector3 baseAxis = head.transform != null ? head.axis : spine.Length > 0 ? spine[spine.Length - 1].axis : root.forward;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (eyes[i].baseForwardOffsetEuler != Vector3.zero) baseRotation *= Quaternion.Euler(eyes[i].baseForwardOffsetEuler);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                Vector3 baseForward = baseRotation * baseAxis;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                GetForwards(ref eyeForward, baseForward, (IKPosition - eyes[i].transform.position).normalized, 1, clampWeightEyes);
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
												// Rotate the eye to face its look at vector
							 | 
						||
| 
								 | 
							
												eyes[i].LookAt(eyeForward[0], eyesWeight * IKPositionWeight);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /*
							 | 
						||
| 
								 | 
							
										 * Returns forwards for a number of bones rotating from baseForward to targetForward.
							 | 
						||
| 
								 | 
							
										 * NB! Make sure baseForward and targetForward are normalized.
							 | 
						||
| 
								 | 
							
										 * */
							 | 
						||
| 
								 | 
							
								        protected Vector3[] GetForwards(ref Vector3[] forwards, Vector3 baseForward, Vector3 targetForward, int bones, float clamp) {
							 | 
						||
| 
								 | 
							
											// If clamp >= 1 make all the forwards match the base
							 | 
						||
| 
								 | 
							
											if (clamp >= 1 || IKPositionWeight <= 0) {
							 | 
						||
| 
								 | 
							
												for (int i = 0; i < forwards.Length; i++) forwards[i] = baseForward;
							 | 
						||
| 
								 | 
							
												return forwards;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											// Get normalized dot product. 
							 | 
						||
| 
								 | 
							
											float angle = Vector3.Angle(baseForward, targetForward);
							 | 
						||
| 
								 | 
							
											float dot = 1f - (angle / 180f);
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											// Clamping the targetForward so it doesn't exceed clamp
							 | 
						||
| 
								 | 
							
											float targetClampMlp = clamp > 0? Mathf.Clamp(1f - ((clamp - dot) / (1f - dot)), 0f, 1f): 1f;
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											// Calculating the clamp multiplier
							 | 
						||
| 
								 | 
							
											float clampMlp = clamp > 0? Mathf.Clamp(dot / clamp, 0f, 1f): 1f;
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											for (int i = 0; i < clampSmoothing; i++) {
							 | 
						||
| 
								 | 
							
												float sinF = clampMlp * Mathf.PI * 0.5f;
							 | 
						||
| 
								 | 
							
												clampMlp = Mathf.Sin(sinF);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											// Rotation amount for 1 bone
							 | 
						||
| 
								 | 
							
											if (forwards.Length == 1) {
							 | 
						||
| 
								 | 
							
												forwards[0] = Vector3.Slerp(baseForward, targetForward, clampMlp * targetClampMlp);
							 | 
						||
| 
								 | 
							
											} else {
							 | 
						||
| 
								 | 
							
												float step = 1f / (float)(forwards.Length - 1);
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
												// Calculate the forward for each bone
							 | 
						||
| 
								 | 
							
												for (int i = 0; i < forwards.Length; i++) {
							 | 
						||
| 
								 | 
							
													forwards[i] = Vector3.Slerp(baseForward, targetForward, spineWeightCurve.Evaluate(step * i) * clampMlp * targetClampMlp);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											return forwards;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /* 
							 | 
						||
| 
								 | 
							
										 * Build LookAtBone[] array of a Transform array
							 | 
						||
| 
								 | 
							
										 * */
							 | 
						||
| 
								 | 
							
								        protected void SetBones(Transform[] array, ref LookAtBone[] bones) {
							 | 
						||
| 
								 | 
							
											if (array == null) {
							 | 
						||
| 
								 | 
							
												bones = new LookAtBone[0];
							 | 
						||
| 
								 | 
							
												return;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											if (bones.Length != array.Length) bones = new LookAtBone[array.Length];
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											for (int i = 0; i < array.Length; i++) {
							 | 
						||
| 
								 | 
							
												if (bones[i] == null) bones[i] = new LookAtBone(array[i]);
							 | 
						||
| 
								 | 
							
												else bones[i].transform = array[i];
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 |