Search Unity

Question Problem rotating an object on its local orientation

Discussion in 'Scripting' started by D_4rk, Dec 5, 2022.

  1. D_4rk

    D_4rk

    Joined:
    Feb 26, 2022
    Posts:
    35
    Hello i am new in the forum! I hope i am in the right section! Im trying to rotate a camera (that rapresent the player POV) using the mouse delta and im rotating the camera in local coordinates not world coordinates and i want avoid gimbal lock effect. I read somewhere on the internet that for that purpose i have to use quaternions, and i read how to do that. The problem is that axis rotations works well moving in local orientation but one of the axis is losing its local orientation and it rotate following the world coordinates orientation. I will post the code and i hope someone can help me and telling me where im doing things wrong. Thanks!

    Code (CSharp):
    1. [Header("Camera")]
    2. [SerializeField] private Camera _camera;
    3. [SerializeField] private Vector2 _xMinMaxRotation = new Vector2(-90, 90);
    4. [SerializeField] private Vector2 _yMinMaxRotation = new Vector2(-90, 90);
    5. [SerializeField] private float _mouseXSensistivity = 1;
    6. [SerializeField] private float _mouseYSensistivity = 1;
    7. [SerializeField] private float _mouseZSensistivity = 1;
    8. [SerializeField] private float _xStartRotation = 0;
    9. [SerializeField] private float _yStartRotation = 0;
    10. private Vector2 _mouseDelta;
    11. private float _rotY, _rotX, _rotZ;
    12.  
    13. // Start is called before the first frame update
    14. void Start() {
    15.     Cursor.lockState = CursorLockMode.Locked;
    16. }
    17.  
    18. // Update is called once per frame
    19. void Update() {
    20.     _mouseDelta = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
    21.     MoveCamera();
    22. }
    23.  
    24.  
    25. private void MoveCamera() {
    26.     _rotX += _mouseDelta.x * _mouseXSensistivity * Time.deltaTime * 100;
    27.     _rotX = Mathf.Clamp(_rotX, _xMinMaxRotation.x, _xMinMaxRotation.y);
    28.     _rotY += _mouseDelta.y * _mouseYSensistivity * Time.deltaTime * 100;
    29.     _rotY = Mathf.Clamp(_rotY, _yMinMaxRotation.x, _yMinMaxRotation.y);
    30.  
    31.     //Calculation for RotZ
    32.     if (Input.GetKey(KeyCode.Q)) {
    33.         _rotZ += +_mouseZSensistivity * Time.deltaTime * 50;
    34.         if (_rotZ > 25) _rotZ = 25;
    35.     }
    36.     else {
    37.         if (_rotZ > 0) {
    38.             _rotZ -= 2 * _mouseZSensistivity * Time.deltaTime * 50;
    39.             if (_rotZ < 0) _rotZ = 0;
    40.         }
    41.     }
    42.     if (Input.GetKey(KeyCode.E)) {
    43.         _rotZ += -_mouseZSensistivity * Time.deltaTime * 50;
    44.         if (_rotZ < -25) _rotZ = -25;
    45.     }
    46.     else {
    47.         if (_rotZ < 0) {
    48.             _rotZ -= 2 * -_mouseZSensistivity * Time.deltaTime * 50;
    49.             if (_rotZ > 0) _rotZ = 0;
    50.         }
    51.     }
    52.  
    53.     Quaternion currentRotation = Quaternion.identity;
    54.     currentRotation = Quaternion.AngleAxis(_rotX, transform.up) * currentRotation;
    55.     currentRotation = Quaternion.AngleAxis(-_rotY, transform.right) * currentRotation;
    56.     currentRotation = Quaternion.AngleAxis(_rotZ, transform.forward) * currentRotation;
    57.     _camera.transform.rotation = currentRotation;
    58. }
    The last part with quaternions is where im trying to calculate angles in order to properly rotate in local coordinates, but as i said there is someting wrong. If i watch the rotation gizmos on the scene of unity sometimes axis are not following the local coordinates.
     
    Last edited: Dec 6, 2022
  2. AlTheSlacker

    AlTheSlacker

    Joined:
    Jun 12, 2017
    Posts:
    326
    Change those last few lines to be:
    Code (CSharp):
    1.         Quaternion currentRotation = Quaternion.identity;
    2.         currentRotation = currentRotation * Quaternion.AngleAxis(_rotX, transform.up) ;
    3.         currentRotation = currentRotation * Quaternion.AngleAxis(-_rotY, transform.right);
    4.         currentRotation = currentRotation * Quaternion.AngleAxis(_rotZ, transform.forward) ;
    5.         _camera.transform.rotation = currentRotation;
     
    D_4rk and jvo3dc like this.
  3. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,478
    This is not a post for the Physics forum. I don't see anything related to physics in it.

    I'll move your post to the Scripting forum.

    It's odd, your previous (necro) post was about physics but you posted it on the Scripting forum. ;)
     
    D_4rk likes this.
  4. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,923
    And if you'd like to not get bogged down in camera work, I suggest using Unity's Cinemachine package.
     
    D_4rk and AlTheSlacker like this.
  5. D_4rk

    D_4rk

    Joined:
    Feb 26, 2022
    Posts:
    35
    Close man! Now the Y and Z axis rotate exactly as i want locally but X rotation looks follow the global X! It's kinda weird!
    There is another oddity in Unity. If i try to rotate an object from another object (like a manager or a parent) it rotate in global coordinates but if i try to rotate the object attaching the SAME script in that object it rotate locally, i mean why? It's looks a bit crazy hehe... This is the function i used in the last problem i described. I It's very similar to the one i'm using for the camera rotation but instead using the delta mouse to calculate the angles i have a fix speed running every frame that represents the angle of rotation.

    Code (CSharp):
    1. public void RotatingWithQuaternion() {
    2.         Quaternion currentRotation = GO_To_Rotate.transform.rotation;
    3.             if (x) {
    4.                 currentRotation = Quaternion.AngleAxis(Time.deltaTime * speed, transform.right) * currentRotation;
    5.             }
    6.             if (y) {
    7.                 currentRotation = Quaternion.AngleAxis(Time.deltaTime * speed, transform.up) * currentRotation;
    8.             }
    9.             if (z) {
    10.                 currentRotation = Quaternion.AngleAxis(Time.deltaTime * speed, transform.forward) * currentRotation;
    11.             }
    12.          
    13.         }
    14.         GO_To_Rotate.transform.rotation = currentRotation;
    15.     }
     
  6. D_4rk

    D_4rk

    Joined:
    Feb 26, 2022
    Posts:
    35
    Thanks and sorry! I was not sure where to post it and i thought rotation and quaternion was somehow releted to phisycs but actually they are more about math and trigonometry filed.
     
    MelvMay likes this.
  7. AnimalMan

    AnimalMan

    Joined:
    Apr 1, 2018
    Posts:
    1,164
    Using Quaternions to avoid Gimbal Lock.

    You're rotating like it's an euler.


    Code (CSharp):
    1. Quaternion.AngleAxis(Time.deltaTime * speed, transform.right) * currentRotation;
    So in euler your * by current rotation is replaced with your Objects.forward, but aside this in euler you are saying Forward = Forward + (Right * (Time * Speed));

    Not sure what you are doing to be honest. There are some Quaternion loyalists floating around that could take you through step by step why its not achieving the result, but from my take it seems like you are using euler technique to rotate in quaternion and this is what's confusing things.
     

    Attached Files:

    Last edited: Dec 6, 2022
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,726
    D_4rk likes this.
  9. D_4rk

    D_4rk

    Joined:
    Feb 26, 2022
    Posts:
    35
    I dont' need this but thanks! I know how to create a fps controller. My problem is very specific and is related to an issue with local rotation. I read many topics and solution about quaternions but none of them is helping me in this specific contest.

    EDIT: Btw the guy in the script you posted me is doing exactly what i am doing but he dosen't have my problem because he moving the camera only in the x and y axis but i move the camera in all 3 axis because i rotate it also with Q and E keybind but the problem is that one of the three axis is not following the local coordinate but the world coordinates.
     
    Last edited: Dec 6, 2022
  10. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,726
    Stack the Transforms so you can control individual local axes with each.

    Player
    CameraLookLeftRightUpDown
    CameraTiltAroundLocalZAxis
    ActualCamera


    Works every time.
     
    D_4rk likes this.