Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Calculate absolute rotation angles above 180 like unity inspector?

Discussion in 'Scripting' started by rnner9000, Sep 6, 2020.

  1. rnner9000

    rnner9000

    Joined:
    Sep 6, 2020
    Posts:
    8
    Hi everyone,

    i build a game where the user can create machines. For that he can rotate a metal plate using rotation handles, similar to the unity editor. After that transform.rotateAround is called to rotate the object around the selected handle axis. Additionaly there is a window to manually type in the rotation in eulerangles.

    Problem: The eulerangles are always between 0 and 180 because of Quaternions. I want to display the angles above 360 in the window. For example (420, 523, 0) after the handle is rotated.

    I triend to do the following to achieve "absolute" rotation angle:
    Code (CSharp):
    1.  
    2. var rotationBefore = transform.localRotation;
    3. transform.RotateAround(point, axis, angle);
    4. var rotationAfter = transform.localRotation;
    5. var delta = rotationBefore * Quaternion.Inverse(rotationAfter);
    6.  
    7. var euler = delta.eulerAngles;
    8. localAbsoluteEulerAngles += euler; // this is displayed in the window
    9.  
    The localAbsoluteEulerAngles are not even matching the actual rotation of the object with this calculation. Also it goes up to 1000+ for an axis after a small rotation. I don't know exactly why. I understand the basics of quaternions and eulerangles. Can someone with more experience explain me why it's not working like that?
     
    Last edited: Sep 6, 2020
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    One way to achieve this is to track your own notion of angle in a float variable that you increase/decrease, so you can control how it wraps/displays, etc. Then you use that angle to produce rotations (using the Quaternion.Euler() factory method, for example) to cause the visible parts of the game to rotate.

    It's always best to control your own data directly, then drive Unity's data one-way, never reading it back if you can avoid it. This is especially true with Quaternions and angles.
     
    Joe-Censored likes this.
  3. rnner9000

    rnner9000

    Joined:
    Sep 6, 2020
    Posts:
    8
    Thank you for your answer. I read more into the topic of euler and quaternions. So as you suggested I use a own notion of angles that capture angles above 360.

    When user rotates a world axis it just increases the axis. However the user rotates objects around any arbitary axis with an angle. Therefore i need a Rotate that works with euler angles and uses angle axis as an input(I was using this post as a reference):

    Code (CSharp):
    1.  
    2. // axis is in world space. The angle is in deg. (object migbt be rotated previously)
    3. public void Rotate(Vector3 axis, float angle)
    4.      {
    5.             angle = angle * Mathf.Deg2Rad;
    6.      
    7.             // YXZ rotation
    8.             float x = axis.x; float y = axis.y; float z = axis.z;
    9.      
    10.             var heading = Mathf.Atan2(y * Mathf.Sin(angle) - x * z * (1 - Mathf.Cos(angle)),
    11.                 1 - (y*y + z*z) * (1 - Mathf.Cos(angle)));
    12.             var attitude = Mathf.Asin(x * y * (1 - Mathf.Cos(angle)) + z * Mathf.Sin(angle));
    13.             var bank = Mathf.Atan2(x * Mathf.Sin(angle) - y * z * (1 - Mathf.Cos(angle)),
    14.                 1 - (x*x + z*z) * (1 - Mathf.Cos(angle)));
    15.          
    16.             var e = new Vector3(bank, heading, attitude) * Mathf.Rad2Deg;
    17.             _eulerAnglesHint += e; // increase or decrease for the angle axis rotation => shown in game window
    18.  
    19.             // apply rotation to transform in XYZ order
    20.             var r = Quaternion.AngleAxis(value.x, Vector3.right) *
    21.                        Quaternion.AngleAxis(value.y, Vector3.up) *
    22.                        Quaternion.AngleAxis(value.z, Vector3.forward);
    23.             transform.rotation = r;
    24.      }
    25.  
    This seams to work if the user at first rotates along the X, then Y and Z axis. However for any arbitary axis that is not the world axis this produces wrong rotations.

    I read for some hours for a solution without success. Maybe the order of XYZ is incorrect (I already tried diefferent orders when calculating r). I would appreachiate if you could help me with this.
     
    Last edited: Sep 23, 2020
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    Fairly sure the multiplicative construct listed on line 20 is not going to get you what you want.

    Quaternion.AngleAxis()
    takes a single argument that is how many degrees around the axis, and a Vector3 that is the axis. This is NOT the same as applying three separate x,y,z values around the cartesian coordinates, as multiplying across quaternions is not distributive, at least I don't think it is. Some mathematician can correct me here.

    SO... pick a vector... that's an axis, like an axle in space... a broomstick... now spin a certain number of degrees around that axis. THAT's what Quaternion.AngleAxis() does, so you can see why choosing three different broomsticks and rotating each one in order won't be distributive.