Search Unity

Problem with getting correct values using localEulerAngles and localRotation

Discussion in 'Scripting' started by Vit3D, Aug 12, 2016.

  1. Vit3D

    Vit3D

    Joined:
    May 2, 2015
    Posts:
    64
    Greetings,

    I work at script for control skeleton bone rotation in Play Mode.
    I'm new in codding for Unity, so first of all I decided to check how I can read local bone rotation in animation.
    If I'm not mistaken Unity provide two ways to read local rotation values - transform.localEulerAngles and transform.localRotation.

    To test both of them I made small script:
    Code (CSharp):
    1. // Read and Dump local rotations
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class ReadRotation : MonoBehaviour {
    6. // Vars
    7. //    Default : gameObject, transform
    8.     private Vector3 current_localEuler;
    9.     private Quaternion current_localRotation;
    10.  
    11.     public void Start () {
    12.         Debug.Log( "Local Rotations Dump:");
    13.     }
    14.     void LateUpdate() {
    15.         current_localEuler = transform.localEulerAngles;
    16.         current_localRotation = transform.localRotation;
    17.         // Debug
    18.         Debug.Log( "Local Euler Rot: " + current_localEuler.x + " : " + current_localEuler.y + " : " + current_localEuler.z );
    19.         Debug.Log( "Local Rotation : " + ConvToDegree(current_localRotation.x) + " : " + ConvToDegree(current_localRotation.y) + " : " + ConvToDegree(current_localRotation.z));
    20.     }
    21.     private float ConvToDegree(float rot) {
    22.         rot = rot * 180;
    23.         if (rot >= 360) {
    24.             rot -= 360;
    25.         }
    26.         else {
    27.             if (rot <= -360) {
    28.                 rot += 360;
    29.             }
    30.         }
    31.         return (rot);
    32.     }
    33. }
    Also I prepared simple construction which consists of two objects -- Parent and Child (Child parented to Parent).
    Both Parent and Child have exactly the same rotation. Then I exported this contraction without animation (base FBX) and prepare test animation.
    In animation Child object has fixed rotation by local Y axis (in all frames) and rotation by local X axis from 0 (fist frame) to 180 (last frame). I exported this animation in separate file (animation FBX).
    In Unity I add my construction without animation to scene, attach ReadRotation script to Child object and apply animation I described above.
    Then I start play and got some sort of dump of rotation values of Child object in local coordinates.

    Values from both transform.localEulerAngles and transform.localRotation surprised me:

    from localEulerAngles :
    At beginning values from localEulerAngles look as expected -- rotation values for local Y and Z are static (fixed) and rotation values for local X increased from frame to frame.
    But after local X rotation reached 90 degree local Y and Z values "jumped" to different static values and local X rotation value begin to decrease.

    from localRotation:
    These values have no "jump" at 90 degree, but all values (for X, Y and Z) changed from frame to frame although in my animation Child object rotated around local X axis only.
    Also even at beginning of animation (before "jump") values from transform.localEulerAngles and transform.localRotation are different. Why?

    Remark:
    I made another test with different animation and in this animation Child object has no rotation by Y and Z and only animated rotation by X.
    With this animation I also got "jump" at 90 degree in values from localEulerAngles but values from transform.localRotation looks rather correct -- as expected only one value changed from frame to frame. But this test is very "synthetic" and such situation practically impossible for real animations.


    Unfortunately I did not find how to fix "jump" problem for values from localEulerAngles and/or modify values from localRotation to have correct local rotation information.
    If someone know how to solve this problem, please share.
    Any information and/or suggestions will be very helpful!

    Cheers,
     
  2. Joaquito

    Joaquito

    Joined:
    Mar 13, 2017
    Posts:
    2
    The whole angle system in Unity is messed up. I should recommend making all the angle-related equations yourself because even though Math IS hard and complicated, it is more time wasting to mess with the crap Unity is in regard to angles.
     
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,539
    euler angles are flawed

    For any given orientation, there are numerous 'euler angles' that could describe that same orientation.

    Sure your current oritentation was the result of 1 turn of 90 degrees around the x-axis... or was it 3 turns -270 around x, 270 around y, and -90 around z.

    They're both the same orientation, but got their 2 different ways.

    Unity doesn't store the history of the turns (that'd take up way too much memory), it's just the current orientation, and that's it.

    FURTHERMORE

    It doesn't store it as euler angles. It stores it as a Quaternion, because Quaternions are really really REALLY good at storing rotations. They have a set of arithmetic operations that work really well, and they don't suffer from things like gimbal lock.

    So when you read 'eulerAngles', really... you're converting the quaternion to a set of euler angles. And the algorithm used may not respect the exact turns you took to get to that orientation.

    How a lot of us get around it.... we don't use euler angles. I almost NEVER use euler angles. I say almost only because that when I'm in the inspector and I orient something... I'm technically modifying euler angles. But I honestly don't pay attention to them, I just wiggle the thing around until it looks good regardless of the angles. And I certainly don't consider euler angles algorithmically.

    And honestly, euler angles suck algorithmically.

    When I'm writing code I'm using describing changes in rotation, not orientations of rotation.

    A 'delta rotation'.

    And really... that's what a quaternion IS. It's why they rock at representing rotation. They're like what vectors do for euclidean motion, but for rotation. They represent a CHANGE in position, not a position in and of itself... now change the word position with rotation.
     
    StarManta likes this.
  4. Vit3D

    Vit3D

    Joined:
    May 2, 2015
    Posts:
    64
    Joaquito and lordofduct, many thanks for replies.

    Think I should explain what for I need such script -- I need controller for skeleton twist bones for more smooth mesh deformation in motions. As You know it's very easy to create such controller in 3ds Max, but not in Unity.
    Good result can be reached if to have only one twist bone linked to main bone and rotation of this bone should be twice slower that rotation of parent main bone.
    Because twist bone linked to main bone for such effect I should apply -0.5*<main bone rotation> (for only one local coordinate)
    So how to use "delta rotation" in this case?

    Cheers,