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

Question Degrees per axis

Discussion in 'Scripting' started by Hummy91, Mar 11, 2023.

  1. Hummy91

    Hummy91

    Joined:
    Jun 7, 2017
    Posts:
    62
    Does anyone have any functional code to grab the degrees of rotation PER axis, for all three axis from a transform? I'm tired of fighting with Quaternions and Eulers. I can accurately achieve this for two axis using eulerAngles but obviously the third breaks down due to how those work and I'm not sure it's possible to get degrees per axis from a quat?

    My use case is creating a custom corrective morph driver that can detect the change in degrees of a transform around any of its local axis to drive different blendshapes. I've tried every approach at this point and fallen short. I'm leaning towards the "track the rotation of the transform yourself" approach however I don't know how to achieve this with quaternions as I need degrees moved, if you try with EulerAngles, you end up with the inevitable wrap around which breaks your delta tracking.
     
  2. LethalGenes

    LethalGenes

    Joined:
    Jan 31, 2023
    Posts:
    69
    Have you written any rotational code before?

    There is nothing easier than working with Euler angles. There must be something wrong with the way you use them.

    You are wanting a 360 degree result from 3 axis’, it’s up, it’s right and it’s forwards just like the Unity inspector uses when positioning and rotating our objects and prefabs!

    this is often the simplest way to position and rotate the object!

    So if I ask you to write me some rotation script that tries to rotate an object with Euler angles, could you show me your script and I will explain why it does not work.
     
  3. chemicalcrux

    chemicalcrux

    Joined:
    Mar 16, 2017
    Posts:
    717
    Euler angles can get non-intuitive thanks to stuff like gimbal lock.

    Perhaps you'd be better served by checking how well a vector aligns with a bunch of other vectors? This way, you aren't worrying about specific rotation values -- you just care about the overall orientation. I mocked it up in Blender real quick..

    upload_2023-3-11_14-5-0.png

    In this case, the input is very close to Shape 1, kind of close to Shape 2, and pretty far from Shape 3.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,749
    Building on this, I use this for the stability system in my Jetpack Kurt Space Flight game.

    The ship can basically tumble any which way you want.

    But when you engage stability and the up is pointing up, I use the .y component of the transform.right to determine roll stability, and the .y component of transform.forward to determine pitch stability.

    For instance, as long as transform.up.y is positive, then if transform.forward.y is negative, it means your nose is below the horizon, you must lift your nose.

    This is effectively comparing it to the world horizon.

    When transform.up.y is negative, everything reverses so if I wanted to stabilize you upside-down, I would feed opposite roll thruster inputs in.
     
  5. Hummy91

    Hummy91

    Joined:
    Jun 7, 2017
    Posts:
    62
    This is effectively what I did and managed to get the exact degrees of motion for two axis, x and z. However this method falls apart for me when trying to get the y or twist in my case because if the x and z have non zero rotation then I'd have to sort of inverse rotate from those to get precisely the y alone. This is something I've tried but had no luck with.
     
  6. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    Your delta tracking is to blame. Try doing SignedAngle instead of eulerAngles if you don't understand it.
    Make sure that the rotation axis is truly axis-aligned, and simply produce the vectors out of the existing quaternion.

    I'm lazy to make you a working example out of this, so let me find you a spherical coord function I did earlier.
    Code (csharp):
    1. using System;
    2. using UnityEngine;
    3.  
    4. static public class MyGeometryExtensions {
    5.  
    6.   private const float PI_TWICE = 2f * Mathf.PI;
    7.   private const float PI_HALF = Mathf.PI / 2f;
    8.  
    9.   static public bool ToSphericalCoords(this Vector3 v, out Vector2 spherical, float magnitude = 1f) {
    10.     var theta = MathF.Atan2(v.z, v.x);
    11.     theta = theta < 0f? theta + PI_TWICE : theta;
    12.     var im = (magnitude == 1f)? 1f : sz(1f / MathF.Max(0f, magnitude), float.NaN);
    13.     var phi = PI_HALF - MathF.Acos(v.y * im);
    14.     var success = true;
    15.     if(float.IsNaN(theta)) { theta = 0f; success = false; }
    16.     if(float.IsNaN(phi)) { phi = 0f; success = false; }
    17.     spherical = new Vector2(theta, phi);
    18.     return success;
    19.  
    20.     // substitute zero
    21.     static float sz(float n, float s) => Math.Abs(n) < 1E-5f? s : n;
    22.   }
    23.  
    24.   static public Vector3 FromSphericalCoords(Vector2 coords)
    25.     => FromSphericalCoords(coords.x, coords.y);
    26.  
    27.   static public Vector3 FromSphericalCoords(float theta, float phi) {
    28.     var th = Polar(theta); var ph = Polar(PI_HALF - phi);
    29.     return new Vector3(th.x * ph.y, ph.x, th.y * ph.y);
    30.   }
    31.  
    32.   static public Vector2 Polar(float theta)
    33.     => new Vector2(MathF.Cos(theta), MathF.Sin(theta));
    34. }
    If you imagine a classic sphere wireframe, sliced in such a way to show graticules, here theta and azimuth (or x and y when it's Vector2) refer to the following angles:
    - theta is also known as a "polar angle" and it's the angle when viewed from above (yaw), going from 0 to 2PI.
    - azimuth is observed from the side, and it's the angle that deviates from the equator (pitch), going from -PI/2 to PI/2 where 0 represents the equator.

    You can perfectly describe any (edit: well, see the next post) rotation by using these two coordinates, as this is what longitude and latitude do geographically.

    Here's a use example, showing that you can start from quaternion, and consistently compute a quaternion back out of it
    Code (csharp):
    1. var baseVec = Vector3.right;
    2. var myQuat = Quaternion.Euler(0f, 45f, 30f);
    3. var dir = myQuat * baseVec;
    4.  
    5. if(dir.ToSphericalCoords(out var sphCoords)) {
    6.   var pt = MyGeometryExtensions.FromSphericalCoords(sphCoords);
    7.   var roundTrip = Quaternion.FromToRotation(baseVec, pt);
    8.   Debug.Log(Quaternion.Dot(myQuat, roundTrip)); // should print out "1" which means the two rotations are equal
    9.   Debug.Log($"theta {coords.x * Mathf.Rad2Deg} azimuth {coords.y * Mathf.Rad2Deg}");
    10.  
    11. } else {
    12.   Debug.Log("Failed to produce valid coords.");
    13.  
    14. }
    edit: oops, forgot some code.
     
    Last edited: Mar 11, 2023
  7. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    However with the above approach you're still supposed to care about the local "roll" of the object, if you need this.

    It's fairly easy to isolate the roll in object space, however I don't have a working example nearby, and you'll have to learn more about how quaternions work anyway. Essentially you'd have to learn how to subtract two rotations, and this is generally achieved by multiplying two quaternions, but you first take an inverse of one of them. In this way, you can locally discard the unwanted rotations. You may want to try and search for my turret behavior code I shared here, because it showcases exactly the kind of operations that you need. I think it's called exactly like that.
     
  8. LethalGenes

    LethalGenes

    Joined:
    Jan 31, 2023
    Posts:
    69
    Remember the change of degrees of a transform, can be measured by storing the degree that the transform started on and comparing the two.

    the only way Euler angle lock is encountered is if you are not preparing your vector 3 correctly before setting your Euler angles to it. This is why it’s important to analyse whether or not you have even used Euler angles correctly before writing them off as a path of solution.
     
  9. Hummy91

    Hummy91

    Joined:
    Jun 7, 2017
    Posts:
    62
    That's where I was stuck at. I basically can get the exact angles/degree changes I need via SignedAngle on a combination of the transforms directions and it's parent as reference. This works fine for x and z but seems to be impossible for y without doing some kind of inverse rotation first. What I tried was taking the x and z angles, and rotating the transform forward with an inverse Quaternion.AngleAxis. So that I'd have an axis aligned rotation along the Y but it just fell over and gave me unexpected results.
     
  10. Hummy91

    Hummy91

    Joined:
    Jun 7, 2017
    Posts:
    62
    I had a quick search and didnt find anything with "turret behaviour" but it does sound like isolating the roll in object space correctly is where Im failing.
     
  11. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    Here you go. It's a literal book, I'm sorry, but there's a lot more packed in that thread than just what you need. So take your time, I am certain that it covers whatever else you might need, by the end of it.

    edit:
    The interesting bits (for your case) begin at post #14
    Also you can grab a full script in post #48 but I'd advise you to get a good grip on what's going on, because everything I do with the quaternions is explained somewhere in that thread.
     
    Last edited: Mar 12, 2023
  12. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    Honestly I'd hack something for you, but I really don't have the time, and this tends to be fiddly, you just have to experiment with it. But the core idea is to take the final rotation and then cancel from it the rotations that are making it tumble, and thus hard to measure with Euler angles. Basically you 'unrotate' your whole frame of reference by what is known, to leave only what is unknown in some axis-aligned space, if you get what I mean. Then when you extract the angles, one (or even two) of the components should be consistently at 0, making your readings stable.

    It's definitely a lot simpler in action, than when I try to explain it, so be stubborn and I'm sure you'll learn a lot about some advanced quaternion techniques. I'll try to find some sample code I did last year for someone else, it was an avatar walking freely on a globe, that sample scene was full of crazy quat shenanigans.
     
  13. Hummy91

    Hummy91

    Joined:
    Jun 7, 2017
    Posts:
    62
    No that makes perfect sense, I already had a good grasp of what I needed to do just couldn't figure out the how with Quaternions, thank you for the help! I'm sure I'll figure it out now
     
    orionsyndrome likes this.