Search Unity

How to record Sphere A's Delta Rotation, relative to Sphere B's local Y Axis?

Discussion in 'Scripting' started by Tset_Tsyung, Feb 1, 2021.

  1. Tset_Tsyung

    Tset_Tsyung

    Joined:
    Jan 12, 2016
    Posts:
    411
    Hey all,

    Okay, trudging through mud, not found the solution on Google or Unity's Quaternion API reference... but I know I'm missing something...

    I want to measure how much Sphere A has rotated over the last frame. However I don't care about the full value (as you get with Quaternion.Angle), what I want is how much it has rotated according to Sphere B's Y axis.

    This is so I can measure how much a VR user has rotated a dial. This isn't rocket science stuff and I'm kicking myself for not figuring it out or already knowing this stuff by heart (I really should read a whole "Game Maths" book)...

    As always, you all rock and I appreciate any and all replies.

    Mike.

    P.S.

    I have been experimenting with "deltaRot = Quaternion.Invers(sphereBRotation) * sphereARotation;". However when trying to extract just the Y axis information, if sphereA has rotated a bit on sphereB's X axis, the Y reading can jump from 0 straight to 180 (despite no y axis rotation happening) due to the quirks of converting Quaternions to Eulers...

    Edit 01/02/21 @ 16:19
    [Sigh] I think I actually have it... I believe I take the result from Quaternion.Inverse(sphereBRotation) * sphereARotation and simply extract the Y Value... is that correct?
     
    Last edited: Feb 1, 2021
  2. Ray_Sovranti

    Ray_Sovranti

    Joined:
    Oct 28, 2020
    Posts:
    172
    The first step (the Inverse part) is correct, but the second is problematic.

    I'm assuming that you mean .eulerAngles.y (because just .y would be giving you apparent gibberish) -- Doing that may work in some situations but you will run into strange bugs because Euler angles are terrible. (That link includes examples of alternatives that you should be able to adapt to this situation)
     
  3. Tset_Tsyung

    Tset_Tsyung

    Joined:
    Jan 12, 2016
    Posts:
    411
    Hi @Ray_Sovranti ,

    Many thanks for your reply. I read over that article your linked to. However I think I either A) am still missing something (see implementation below) or B) it will still cause similar issues...

    Here's my test script:
    Code (CSharp):
    1. public class WorldToLocalRotationChecker : MonoBehaviour
    2. {
    3.     [SerializeField] private Transform targetTransform = default;
    4.  
    5.     Quaternion rotFirstFrame;
    6.     Quaternion rotThisFrame;
    7.  
    8.     private void Start()
    9.     {
    10.         // Get the 'local' rotation at the time of the initial grab (at start for test purposes)
    11.         rotFirstFrame = Quaternion.Inverse(transform.rotation) * targetTransform.rotation;
    12.     }
    13.  
    14.     void Update()
    15.     {
    16.         // Get the 'local' rotation this frame
    17.         rotThisFrame = Quaternion.Inverse(transform.rotation) * targetTransform.rotation;
    18.  
    19.         // Now work out the rotational delta from the original to current frame rotations
    20.         Quaternion rotOverTime = Quaternion.Inverse(rotFirstFrame) * rotThisFrame;
    21.  
    22.         /// But what comes next?
    23.     }
    24. }
    I've prepared a short video to explain what I'm after (I am concerned I didn't explain myself well)



    Also, there seems to be an issue with the code on that page - when testing I would when I have a rotation of 0,0,0. When I would run the code below (as per the article) the variable 'angleInDegrees' would have a value of 90, despite the transform having a rotation of 0,0,0.
    Code (CSharp):
    1. Vector3 forward = transform.forward;
    2. float angleInDegrees = Mathf.Atan2(forward.z, forward.x) * Mathf.Rad2Deg;
    I sincerely hope that my questions and concerns don't exasperate you - I honestly appreciate your input.

    Thanks again ;)
     
  4. Ray_Sovranti

    Ray_Sovranti

    Joined:
    Oct 28, 2020
    Posts:
    172
    Once you have the rotOverTime, I think that's what you'll want to use as the basis for the rotated vector. Something along the lines of:
    Code (csharp):
    1. Vector3 dialRight = rotOverTime * Vector3.right;
    2. float angleInDegrees = Mathf.Atan2(dialRight.y, dialRight.x);
    Maybe. I'm not exactly sure how you have all the rotations set up, so the axes and stuff may all need to be tweaked, but rotOverTime is probably where you need to base it.