Skip to content

Instantly share code, notes, and snippets.

@D4KU
Created August 16, 2022 22:17
Show Gist options
  • Select an option

  • Save D4KU/c71c9a0fef4b131b31ecf18b68cdfa07 to your computer and use it in GitHub Desktop.

Select an option

Save D4KU/c71c9a0fef4b131b31ecf18b68cdfa07 to your computer and use it in GitHub Desktop.
Unity clamp rotation to view cone
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