Search code examples
c#unity-game-enginecameragame-developmentquaternions

How to clamp camera rotation axis correctly?


I am trying to clamp the X and Y axis of my camera, which I have managed to do. However, when the clamped value reaches the MAX threshold it will jump back to the MIN threshold! Any idea what is causing this in my code?

 private void ClimbingLookRotation()
    {
        if (input.mouseX != 0 || input.mouseY != 0f)
        {
            orientation.rotation *= Quaternion.AngleAxis(input.mouseX, Vector3.up);
            orientation.rotation *= Quaternion.AngleAxis(input.mouseY, Vector3.right);
        }

        var rotX = orientation.eulerAngles.x;
        var rotY = orientation.eulerAngles.y;

        rotX = Mathf.Clamp(rotX, 1, 25);
        rotY = Mathf.Clamp(rotY, 200, 355);            

        orientation.eulerAngles = new Vector3(rotX, rotY, 0);
    }

Any help would be appreciated! Thankyou.


Solution

  • I found something the works well so thought I'd answer in case it would help anyone!

     public static float ClampAngle(float angle, float min, float max)
        {   //Normalises angle value passed in between -180 to 180 to make the angle clampable
            angle = NormalizeAngle(angle);
            if (angle > 180)
            {
                angle -= 360;
            }
            else if (angle < -180)
            {
                angle += 360;
            }
    
            min = NormalizeAngle(min);
            if (min > 180)
            {
                min -= 360;
            }
            else if (min < -180)
            {
                min += 360;
            }
    
            max = NormalizeAngle(max);
            if (max > 180)
            {
                max -= 360;
            }
            else if (max < -180)
            {
                max += 360;
            }
    
            return Mathf.Clamp(angle, min, max);
        }
    
        public static float NormalizeAngle(float angle)
        { //If the angle is above or below 360 degrees, normalise it
            while (angle > 360)
                angle -= 360;
            while (angle < 0)
                angle += 360;
            return angle;
        }
    

    And then just call the ClampAngle method where ever you need to clamp a value, for example:

    private void ClimbingLookRotation()
        {
            if (input.mouseX != 0 || input.mouseY != 0f)
            {
                orientation.rotation *= Quaternion.AngleAxis(input.mouseX, Vector3.up);
                orientation.rotation *= Quaternion.AngleAxis(input.mouseY, Vector3.right);
            }
    
            var rotX = orientation.eulerAngles.x;
            var rotY = orientation.eulerAngles.y;
    
            rotX = HelperFunctions.ClampAngle(rotX, -10, 25); //Here
            rotY = HelperFunctions.ClampAngle(rotY, 200, 340); //And here
    
            orientation.eulerAngles = new Vector3(rotX, rotY, 0);
        }
    

    I've called it in my camera rotation function to clamp both rotX and rotY, which is later applied to the rotation of my orientation game object.

    Thankyou again to Ruzihm for your help before :)