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.
		
		
		
		
		
			
		
			
	
	
		
			190 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C#
		
	
		
		
			
		
	
	
			190 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C#
		
	
| 
								 
											1 year ago
										 
									 | 
							
								using UnityEngine;
							 | 
						||
| 
								 | 
							
								using System.Collections;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace RootMotion.FinalIK
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /// <summary>
							 | 
						||
| 
								 | 
							
								    /// The base abstract class for all Rotation limits. Contains common functionality and static helper methods
							 | 
						||
| 
								 | 
							
								    /// </summary>
							 | 
						||
| 
								 | 
							
								    public abstract class RotationLimit : MonoBehaviour
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        #region Main Interface
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// The main axis of the rotation limit.
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        public Vector3 axis = Vector3.forward;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// Map the zero rotation point to the current local rotation of this gameobject.
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        public void SetDefaultLocalRotation()
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            defaultLocalRotation = transform.localRotation;
							 | 
						||
| 
								 | 
							
								            defaultLocalRotationSet = true;
							 | 
						||
| 
								 | 
							
								            defaultLocalRotationOverride = false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
										/// Map the zero rotation point to the specified rotation.
							 | 
						||
| 
								 | 
							
										/// </summary>
							 | 
						||
| 
								 | 
							
								        public void SetDefaultLocalRotation(Quaternion localRotation)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            defaultLocalRotation = localRotation;
							 | 
						||
| 
								 | 
							
								            defaultLocalRotationSet = true;
							 | 
						||
| 
								 | 
							
								            defaultLocalRotationOverride = true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// Returns the limited local rotation.
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        public Quaternion GetLimitedLocalRotation(Quaternion localRotation, out bool changed)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            // Making sure the Rotation Limit is initiated
							 | 
						||
| 
								 | 
							
								            if (!initiated) Awake();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Subtracting defaultLocalRotation
							 | 
						||
| 
								 | 
							
								            Quaternion rotation = Quaternion.Inverse(defaultLocalRotation) * localRotation;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            Quaternion limitedRotation = LimitRotation(rotation);
							 | 
						||
| 
								 | 
							
								#if UNITY_2018_3_OR_NEWER
							 | 
						||
| 
								 | 
							
								            limitedRotation = Quaternion.Normalize(limitedRotation);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								            changed = limitedRotation != rotation;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (!changed) return localRotation;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Apply defaultLocalRotation back on
							 | 
						||
| 
								 | 
							
								            return defaultLocalRotation * limitedRotation;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// Apply the rotation limit to transform.localRotation. Returns true if the limit has changed the rotation.
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        public bool Apply()
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            bool changed = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            transform.localRotation = GetLimitedLocalRotation(transform.localRotation, out changed);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return changed;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// Disable this instance making sure it is initiated. Use this if you intend to manually control the updating of this Rotation Limit.
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        public void Disable()
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (initiated)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                enabled = false;
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            Awake();
							 | 
						||
| 
								 | 
							
								            enabled = false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endregion Main Interface
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /*
							 | 
						||
| 
								 | 
							
										 * An arbitrary secondary axis that we get by simply switching the axes
							 | 
						||
| 
								 | 
							
										 * */
							 | 
						||
| 
								 | 
							
								        public Vector3 secondaryAxis { get { return new Vector3(axis.y, axis.z, axis.x); } }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /*
							 | 
						||
| 
								 | 
							
										 * Cross product of axis and secondaryAxis
							 | 
						||
| 
								 | 
							
										 * */
							 | 
						||
| 
								 | 
							
								        public Vector3 crossAxis { get { return Vector3.Cross(axis, secondaryAxis); } }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /*
							 | 
						||
| 
								 | 
							
										 * The default local rotation of the gameobject. By default stored in Awake.
							 | 
						||
| 
								 | 
							
										 * */
							 | 
						||
| 
								 | 
							
								        [HideInInspector] public Quaternion defaultLocalRotation;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public bool defaultLocalRotationOverride { get; private set; }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        protected abstract Quaternion LimitRotation(Quaternion rotation);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private bool initiated;
							 | 
						||
| 
								 | 
							
								        private bool applicationQuit;
							 | 
						||
| 
								 | 
							
								        private bool defaultLocalRotationSet;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /*
							 | 
						||
| 
								 | 
							
										 * Initiating the Rotation Limit
							 | 
						||
| 
								 | 
							
										 * */
							 | 
						||
| 
								 | 
							
								        void Awake()
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            // Store the local rotation to map the zero rotation point to the current rotation
							 | 
						||
| 
								 | 
							
								            if (!defaultLocalRotationSet) SetDefaultLocalRotation();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (axis == Vector3.zero) Debug.LogError("Axis is Vector3.zero.");
							 | 
						||
| 
								 | 
							
								            initiated = true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /*
							 | 
						||
| 
								 | 
							
										 * Using LateUpdate here because you most probably want to apply the limits after animation. 
							 | 
						||
| 
								 | 
							
										 * If you need precise control over the execution order, disable this script and call Apply() whenever you need
							 | 
						||
| 
								 | 
							
										 * */
							 | 
						||
| 
								 | 
							
								        void LateUpdate()
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            Apply();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /*
							 | 
						||
| 
								 | 
							
										 * Logs the warning if no other warning has beed logged in this session.
							 | 
						||
| 
								 | 
							
										 * */
							 | 
						||
| 
								 | 
							
								        public void LogWarning(string message)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            Warning.Log(message, transform);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#region Static helper methods for all Rotation Limits
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /*
							 | 
						||
| 
								 | 
							
										 * Limits rotation to a single degree of freedom (along axis)
							 | 
						||
| 
								 | 
							
										 * */
							 | 
						||
| 
								 | 
							
								        protected static Quaternion Limit1DOF(Quaternion rotation, Vector3 axis)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return Quaternion.FromToRotation(rotation * axis, axis) * rotation;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /*
							 | 
						||
| 
								 | 
							
										 * Applies uniform twist limit to the rotation
							 | 
						||
| 
								 | 
							
										 * */
							 | 
						||
| 
								 | 
							
								        protected static Quaternion LimitTwist(Quaternion rotation, Vector3 axis, Vector3 orthoAxis, float twistLimit)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            twistLimit = Mathf.Clamp(twistLimit, 0, 180);
							 | 
						||
| 
								 | 
							
								            if (twistLimit >= 180) return rotation;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            Vector3 normal = rotation * axis;
							 | 
						||
| 
								 | 
							
								            Vector3 orthoTangent = orthoAxis;
							 | 
						||
| 
								 | 
							
								            Vector3.OrthoNormalize(ref normal, ref orthoTangent);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            Vector3 rotatedOrthoTangent = rotation * orthoAxis;
							 | 
						||
| 
								 | 
							
								            Vector3.OrthoNormalize(ref normal, ref rotatedOrthoTangent);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            Quaternion fixedRotation = Quaternion.FromToRotation(rotatedOrthoTangent, orthoTangent) * rotation;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (twistLimit <= 0) return fixedRotation;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Rotate from zero twist to free twist by the limited angle
							 | 
						||
| 
								 | 
							
								            return Quaternion.RotateTowards(fixedRotation, rotation, twistLimit);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /*
							 | 
						||
| 
								 | 
							
										 * Returns the angle between two vectors on a plane with the specified normal
							 | 
						||
| 
								 | 
							
										 * */
							 | 
						||
| 
								 | 
							
								        protected static float GetOrthogonalAngle(Vector3 v1, Vector3 v2, Vector3 normal)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            Vector3.OrthoNormalize(ref normal, ref v1);
							 | 
						||
| 
								 | 
							
								            Vector3.OrthoNormalize(ref normal, ref v2);
							 | 
						||
| 
								 | 
							
								            return Vector3.Angle(v1, v2);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endregion
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 |