Search code examples
c#unity-game-enginerotationquaternionsclamp

Clamp a quaternion rotation in unity


I have this code but I have not been able to find a decent solution to clamp the X axis between 2 angle values. How would it be done in this case?

public class CameraController : MonoBehaviour {
    public float cameraSmoothness = 5f;

    private Quaternion targetGlobalRotation;
    private Quaternion targetLocalRotation = Quaternion.Identity;

    private void Start(){
        targetGlobalRotation = transform.rotation;
    }

    private void Update(){
        targetGlobalRotation *= Quaternion.Euler(
            Vector3.up * Input.GetAxis("Mouse X"));
        
        targetLocalRotation *= Quaternion.Euler(
            Vector3.right * -Input.GetAxis("Mouse Y"));

        transform.rotation = Quaternion.Lerp(
            transform.rotation,
            targetGlobalRotation * targetLocalRotation,
            cameraSmoothness * Time.deltaTime);
    }
}

Solution

  • For this you would rather use Euler angles and only convert them to Quaternion after applying the clamp!

    Never directly touch individual components of a Quaternion unless you really know exactly what you are doing! A Quaternion has four components x, y, z and w and they all move in the range -1 to 1 so what you tried makes little sense ;)

    It could be something like e.g.

    // Adjust via Inspector
    public float minXRotation = 10;
    public float maxXRotation = 90;
    
    // Also adjust via Inspector
    public Vector2 sensitivity = Vector2.one;
    
    private float targetYRotation;
    private float targetXRotation;
    
    private void Update()
    {
        targetYRotation += Input.GetAxis("Mouse X")) * sensitivity.x;      
        targetXRotation -= Input.GetAxis("Mouse Y")) * sensitivity.y;
    
        targetXRotation = Mathf.Clamp(targetXRotation, minXRotation, maxXRotation);
    
        var targetRotation = Quaternion.Euler(Vector3.up * targetYRotation) * Quaternion.Euler(Vector3.right * targetXRotation);
    
        transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, cameraSmoothness * Time.deltaTime);
    }