Get current rotation from Unity.Mathematics.quaternion

Hi,

I’ve been looking for over an hour now, can’t find a good awnser.

I’m making some sort of bobblehead functionality. So it has to wobble between -5 and 5 degrees on the Z axis.

How do I read the Z axis from a quaternion (Unity.Mathematics.quaternion)?

With kind regards,
Nymo

1 Like

use a vector perpendicular to Z-axis rotate that vector by your quaternion and get rotation from un-rotated to rotate vector. that’s the Z-axis rotation.

Hi @Lieene-Guo , I don’t understand.

Can you please write a piece of code that does that?

I really don’t know how to rotate a vector with a quaternion

        public static quaternion WithOutZAxis(this quaternion rot, out quaternion zRot)
        {
            float3 xAxis = math.float3(1, 0, 0);
            var rotatedX = math.mul(rot, xAxis);
            zRot = FromToRotationAssumeNomalized(xAxis, rotatedX);
            return math.mul(math.inverse(zRot), rot);
        }

        //This is from Unity.Physics
        /// <summary>
        /// fast approach to shortest arc rotaion from a to b
        /// a and b MUST BE NORMALIZED direction
        /// </summary>
        public static quaternion FromToRotationAssumeNomalized(float3 from, float3 to)
        {
            float d = math.dot(from, to);
            if (d == 1) { return quaternion.identity; }
            float4 q = math.float4(math.cross(from, to), 1f + d);
            math.normalize(q);
            return math.quaternion(q);
        }
1 Like

Hi @Lieene-Guo , I really appreciate you helping me and writing code. I just don’t know how to work with this. I tried a couple of things with it. I get that it returns a quaternion with and without the z axis, and bij subtracting the two the result is a quaternion that only represents the z axis. But that’s in 4 floats. And I really only want one float, if it’s degrees or radians doesn’t matter. just a single float. can you help me with that?

this part: float d = math.dot(from, to); give you sin value of the angle you want.

Hi @Lieene-Guo , thanks again.

I guess you have written a whole library that does these kinds of things, with the “MathX” reference :wink:
I don’t know how to use it still, it must be basic for you but this kind of “advanced” math, is not yet part of my education.

Unity.Mathematics.quaternion stores radians instead of degrees. And after testing different kins of sin,cosin etc. methods and translating the result to degrees, I don’t see anything that looks like a value I was testing for.

I think there must be a simple way of seeing what the current stored radians or degrees are from a quaternoin. So I probably missed something.

@MartinGram , @Joachim_Ante_1 , @Daniel-Brauer

Sorry for tagging you guys but can one of you help me out? What is the way of reading the current stored rotation in either degrees or radians?

In 2D you can represent rotations using angles or using complex numbers. Complex numbers add an additional dimension to your mathematics, but avoid trigonometric operations. Complex numbers do not contain information about the number of times something rotates around (there’s no concept of a 720 degree rotation).

Similarly, quaternions also use an additional dimension of imaginary numbers to compute rotations without trigonometry. However, they also avoid other issues like gimbal locking and have slerp capabilities. There is no “angle” stored in a quaternion in the conventional sense.

Assuming that your quaternion was only ever rotated along the z-axis (roll), then if you do this:

var rolledRightVector = math.mul(rot, new float3(1, 0, 0));

The z value of rolledRightVector is now the sine of the z-rotation. If you were to rotate along z by 90 degrees, the z value of rolledRightVector would be 1. If you don’t rotate at all, it would be 0.
So now you can do this:

var zRotationInRadians = math.asin(rolledRightVector.z);
1 Like

Hi @DreamingImLatios , thanks for the solution. I tried it in this way:

quaternion q1 = Unity.Mathematics.quaternion.Euler(0, 0, 5);
var rolledRightVector = math.mul(q1, new float3(1, 0, 0));
var zRotationInRadians = math.asin(rolledRightVector.z);
Debug.Log($“zRotationInRadians: {zRotationInRadians} ___ D: {zRotationInRadians * 57.2957795f}”);

But it doesn’t give me 5. Am I doing it right?

Hi everybody, if it doesn’t matter what the start rotation is, I have made this for the bobble effect:

float maxRotationRadians = punt.MaxDegrees * 0.0174532925f;
float minRotationRadians = -punt.MaxDegrees * 0.0174532925f;
float radiansToAdd = punt.RotationSpeed * Time.DeltaTime;
Entities
.ForEach((ref Translation translation, ref Rotation rotation, ref DataComponent_ShakeRotation dataComponent) =>
{
if (dataComponent.IsMovingRight)
{
rotation.Value = math.mul(math.normalize(rotation.Value), quaternion.AxisAngle(math.forward(rotation.Value), radiansToAdd));
dataComponent.CurrentRotationInRadians += radiansToAdd;
}
else
{
rotation.Value = math.mul(math.normalize(rotation.Value), quaternion.AxisAngle(math.forward(rotation.Value), -radiansToAdd));
dataComponent.CurrentRotationInRadians -= radiansToAdd;
}
if (dataComponent.IsMovingRight && dataComponent.CurrentRotationInRadians > maxRotationRadians)
dataComponent.IsMovingRight = false;
else if (!dataComponent.IsMovingRight && dataComponent.CurrentRotationInRadians < minRotationRadians)
dataComponent.IsMovingRight = true;
})
.ScheduleParallel();

The what now?

It’s my math extension lib. but the function is right under it.

1 Like