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.
		
		
		
		
		
			
		
			
				
	
	
		
			152 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C#
		
	
			
		
		
	
	
			152 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C#
		
	
using UnityEngine;
 | 
						|
using System.Collections;
 | 
						|
 | 
						|
namespace RootMotion.FinalIK {
 | 
						|
 | 
						|
	public class LookAtController : MonoBehaviour {
 | 
						|
 | 
						|
		public LookAtIK ik;
 | 
						|
 | 
						|
		[Header("Target Smoothing")]
 | 
						|
 | 
						|
		[Tooltip("The target to look at. Do not use the Target transform that is assigned to LookAtIK. Set to null if you wish to stop looking.")]
 | 
						|
		public Transform target;
 | 
						|
 | 
						|
		[Range(0f, 1f)] public float weight = 1f;
 | 
						|
 | 
						|
		public Vector3 offset;
 | 
						|
 | 
						|
		[Tooltip("The time it takes to switch targets.")]
 | 
						|
		public float targetSwitchSmoothTime = 0.3f;
 | 
						|
 | 
						|
		[Tooltip("The time it takes to blend in/out of LookAtIK weight.")]
 | 
						|
		public float weightSmoothTime = 0.3f;
 | 
						|
 | 
						|
		[Header("Turning Towards The Target")]
 | 
						|
 | 
						|
		[Tooltip("Enables smooth turning towards the target according to the parameters under this header.")]
 | 
						|
		public bool smoothTurnTowardsTarget = true;
 | 
						|
 | 
						|
		[Tooltip("Speed of turning towards the target using Vector3.RotateTowards.")]
 | 
						|
		public float maxRadiansDelta = 3f;
 | 
						|
 | 
						|
		[Tooltip("Speed of moving towards the target using Vector3.RotateTowards.")]
 | 
						|
		public float maxMagnitudeDelta = 3f;
 | 
						|
 | 
						|
		[Tooltip("Speed of slerping towards the target.")]
 | 
						|
		public float slerpSpeed = 3f;
 | 
						|
 | 
						|
		[Tooltip("The position of the pivot that the look at target is rotated around relative to the root of the character.")] 
 | 
						|
		public Vector3 pivotOffsetFromRoot = Vector3.up;
 | 
						|
 | 
						|
		[Tooltip("Minimum distance of looking from the first bone. Keeps the solver from failing if the target is too close.")] 
 | 
						|
		public float minDistance = 1f;
 | 
						|
 | 
						|
		[Header("RootRotation")]
 | 
						|
		[Tooltip("Character root will be rotate around the Y axis to keep root forward within this angle from the look direction.")]
 | 
						|
		[Range(0f, 180f)]
 | 
						|
		public float maxRootAngle = 45f;
 | 
						|
 | 
						|
		private Transform lastTarget;
 | 
						|
		private float switchWeight, switchWeightV;
 | 
						|
		private float weightV;
 | 
						|
		private Vector3 lastPosition;
 | 
						|
		private Vector3 dir;
 | 
						|
		private bool lastSmoothTowardsTarget;
 | 
						|
 | 
						|
		void Start() {
 | 
						|
			lastPosition = ik.solver.IKPosition;
 | 
						|
			dir = ik.solver.IKPosition - pivot;
 | 
						|
		}
 | 
						|
 | 
						|
		void LateUpdate () {
 | 
						|
			// If target has changed...
 | 
						|
			if (target != lastTarget) {
 | 
						|
                if (lastTarget == null && target != null && ik.solver.IKPositionWeight <= 0f) { 
 | 
						|
                    lastPosition = target.position;
 | 
						|
					dir = target.position - pivot;
 | 
						|
					ik.solver.IKPosition = target.position + offset;
 | 
						|
				} else {
 | 
						|
					lastPosition = ik.solver.IKPosition;
 | 
						|
					dir = ik.solver.IKPosition - pivot;
 | 
						|
				}
 | 
						|
 | 
						|
				switchWeight = 0f;
 | 
						|
				lastTarget = target;
 | 
						|
			}
 | 
						|
 | 
						|
            // Smooth weight
 | 
						|
            float targetWeight = target != null ? weight : 0f;
 | 
						|
			ik.solver.IKPositionWeight = Mathf.SmoothDamp(ik.solver.IKPositionWeight, targetWeight, ref weightV, weightSmoothTime);
 | 
						|
			if (ik.solver.IKPositionWeight >= 0.999f && targetWeight > ik.solver.IKPositionWeight) ik.solver.IKPositionWeight = 1f;
 | 
						|
			if (ik.solver.IKPositionWeight <= 0.001f && targetWeight < ik.solver.IKPositionWeight) ik.solver.IKPositionWeight = 0f;
 | 
						|
 | 
						|
			if (ik.solver.IKPositionWeight <= 0f) return;
 | 
						|
 | 
						|
			// Smooth target switching
 | 
						|
			switchWeight = Mathf.SmoothDamp(switchWeight, 1f, ref switchWeightV, targetSwitchSmoothTime);
 | 
						|
			if (switchWeight >= 0.999f) switchWeight = 1f;
 | 
						|
 | 
						|
			if (target != null) {
 | 
						|
				ik.solver.IKPosition = Vector3.Lerp(lastPosition, target.position + offset, switchWeight);
 | 
						|
			}
 | 
						|
 | 
						|
			// Smooth turn towards target
 | 
						|
			if (smoothTurnTowardsTarget != lastSmoothTowardsTarget) {
 | 
						|
				dir = ik.solver.IKPosition - pivot;
 | 
						|
				lastSmoothTowardsTarget = smoothTurnTowardsTarget;
 | 
						|
			}
 | 
						|
 | 
						|
			if (smoothTurnTowardsTarget) {
 | 
						|
				Vector3 targetDir = ik.solver.IKPosition - pivot;
 | 
						|
				dir = Vector3.Slerp(dir, targetDir, Time.deltaTime * slerpSpeed);
 | 
						|
				dir = Vector3.RotateTowards(dir, targetDir, Time.deltaTime * maxRadiansDelta, maxMagnitudeDelta);
 | 
						|
				ik.solver.IKPosition = pivot + dir;
 | 
						|
			}
 | 
						|
 | 
						|
			// Min distance from the pivot
 | 
						|
			ApplyMinDistance();
 | 
						|
 | 
						|
			// Root rotation
 | 
						|
			RootRotation();
 | 
						|
		}
 | 
						|
 | 
						|
		// Pivot of rotating the aiming direction.
 | 
						|
		private Vector3 pivot {
 | 
						|
			get {
 | 
						|
				return ik.transform.position + ik.transform.rotation * pivotOffsetFromRoot;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Make sure aiming target is not too close (might make the solver instable when the target is closer to the first bone than the last bone is).
 | 
						|
		void ApplyMinDistance() {
 | 
						|
			Vector3 aimFrom = pivot;
 | 
						|
			Vector3 direction = (ik.solver.IKPosition - aimFrom);
 | 
						|
			direction = direction.normalized * Mathf.Max(direction.magnitude, minDistance);
 | 
						|
				
 | 
						|
			ik.solver.IKPosition = aimFrom + direction;
 | 
						|
		}
 | 
						|
 | 
						|
		// Character root will be rotate around the Y axis to keep root forward within this angle from the looking direction.
 | 
						|
		private void RootRotation() {
 | 
						|
			float max = Mathf.Lerp(180f, maxRootAngle, ik.solver.IKPositionWeight);
 | 
						|
 | 
						|
			if (max < 180f) {
 | 
						|
				Vector3 faceDirLocal = Quaternion.Inverse(ik.transform.rotation) * (ik.solver.IKPosition - pivot);
 | 
						|
				float angle = Mathf.Atan2(faceDirLocal.x, faceDirLocal.z) * Mathf.Rad2Deg;
 | 
						|
 | 
						|
				float rotation = 0f;
 | 
						|
 | 
						|
				if (angle > max) {
 | 
						|
					rotation = angle - max;
 | 
						|
				}
 | 
						|
				if (angle < -max) {
 | 
						|
					rotation = angle + max;
 | 
						|
				}
 | 
						|
 | 
						|
				ik.transform.rotation = Quaternion.AngleAxis(rotation, ik.transform.up) * ik.transform.rotation;		
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |