Created
August 16, 2022 22:17
-
-
Save D4KU/c71c9a0fef4b131b31ecf18b68cdfa07 to your computer and use it in GitHub Desktop.
Unity clamp rotation to view cone
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using UnityEngine; | |
| /// <summary> | |
| /// Clamps its local rotation to a view cone. Think of the view cone of a | |
| /// spot light. | |
| /// </summary> | |
| [ExecuteAlways] | |
| public class ClampRotationToCone : MonoBehaviour | |
| { | |
| public enum Axis | |
| { | |
| Forward, | |
| Backward, | |
| Right, | |
| Left, | |
| Up, | |
| Down, | |
| } | |
| [Tooltip("Local direction vector to be clamped inside cone")] | |
| public Axis axis; | |
| [Tooltip("Direction from view cone tip to center of base circle, in local space")] | |
| public Vector3 coneAxis = Vector3.forward; | |
| [Tooltip("Max angle allowed for direction to differ from cone axis, in degree")] | |
| public float maxAngle = 45f; | |
| void Update() | |
| { | |
| // Rotation from forward vector to look direction in local space | |
| Quaternion pre = axis switch | |
| { | |
| Axis.Forward => Quaternion.identity, | |
| Axis.Right => Quaternion.Euler(0, 90, 0), | |
| Axis.Up => Quaternion.Euler(-90, 0, 0), | |
| Axis.Backward => Quaternion.Euler(0, 180, 0), | |
| Axis.Left => Quaternion.Euler(0, -90, 0), | |
| Axis.Down => Quaternion.Euler(90, 0, 0), | |
| _ => throw new InvalidOperationException(), | |
| }; | |
| // Pre rotation in coordinate system of parent | |
| Quaternion pre2 = transform.localRotation * pre; | |
| // Direction to clamp and up direction in parent space | |
| Vector3 up = pre2 * Vector3.up; | |
| Vector3 look = pre2 * Vector3.forward; | |
| // Clamped angle between cone axis and look direction | |
| float angle = Mathf.Min(Vector3.Angle(coneAxis, look), maxAngle); | |
| // Axis to rotate from cone axis to look rotation | |
| Vector3 deltaAxis = Vector3.Cross(coneAxis, look); | |
| // Delta rotation between cone axis and look direction | |
| Quaternion delta = Quaternion.AngleAxis(angle, deltaAxis); | |
| // 1. Look with forward vector to the delta from the cone axis | |
| // 2. Keep up direction to keep roll | |
| // 3. Make actual look direction instead of forward vector face delta | |
| // direction | |
| transform.localRotation = Quaternion.LookRotation(delta * coneAxis, up) | |
| * Quaternion.Inverse(pre); | |
| } | |
| #if UNITY_EDITOR | |
| void OnDrawGizmosSelected() | |
| { | |
| Vector3 pos = transform.position; | |
| const float TIP_RADIUS = .02f; | |
| Gizmos.color = Color.red; | |
| Gizmos.DrawLine(pos - transform.right, pos + transform.right); | |
| Gizmos.DrawSphere(pos + transform.right, TIP_RADIUS); | |
| Gizmos.color = Color.green; | |
| Gizmos.DrawLine(pos - transform.up, pos + transform.up); | |
| Gizmos.DrawSphere(pos + transform.up, TIP_RADIUS); | |
| Gizmos.color = Color.blue; | |
| Gizmos.DrawLine(pos - transform.forward, pos + transform.forward); | |
| Gizmos.DrawSphere(pos + transform.forward, TIP_RADIUS); | |
| } | |
| #endif | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment