2
votes

I need to display the rotation in Euler angles of an object's certain axis. I am aware that retrieving the rotation of an object in Euler angles gives inconsistent results, some of which can be solved by simply using modulo 360 on the result. however one permutation that unity sometimes does when assigning a vector with the value of "transform.localRotation.eulerAngles" is instead of retrieving the Vector3 "V", it retrieves "(180, 180, 180) - V". to my understanding, "(180, 180, 180) - V" does not result in the same real world rotation as V, unlike "(180, 180, 180) + V" which does leave the actual rotation unaffected. what is the explanation for the phenomenon, and what is the best way of normalizing an Euler angles rotation vector assuming I know the desired and feasible value of one of its axes? (for example, to normalize it such that all of it's values are mod 360 and it's Z axis equals 0 assuming it does have a representation in which Z = 0)

2
"one permutation that unity sometimes does when ... " - can you quote the source for this?meowgoesthedog

2 Answers

1
votes

I don't know about the first part of the question (it is different enough to be its own question imo) but I can answer your second one.

So, you have these inputs :

Quaternion desiredRotation;
float knownZ;

And you're trying to find Vector3 eulers where eulers.z is approximately knownZ and Quaternion.Euler(eulers) == desiredRotation.

Here's the procedure I would use:


First, determine the up direction rotated by desiredRotation and the up and right direction rotated by a roll of knownZ:

Vector3 upDirEnd = desiredRotation * Vector3.up;

Quaternion rollRotation = Quaternion.Euler(0,0,knownZ);
Vector3 upDirAfterRoll = rollRotation  * Vector3.up;
Vector3 rightDirAfterRoll = rollRotation * Vector3.right;

We know the local up direction after desiredRotation is applied and that the only thing that can adjust the up direction after the roll knownZ is applied is the rotation done by the euler pitch component. So, if we can calculate the angle from upDirAfterRoll to upDirEnd as measured around the rightDirAfterRoll axis...

float determinedX = Vector3.SignedAngle(upDirAfterRoll, upDirEnd, rightDirAfterRoll);
// Normalizing determinedX
determinedX = (determinedX + 360f) % 360f;

...we can determine the x component of eulers!

Then, we do the same with the yaw component of eulers to make the new forward direction line up with the end forward direction:

Vector3 forwardDirEnd = desiredRotation * Vector3.forward;

Quaternion rollAndPitchRotation = Quaternion.Euler(determinedX, 0, knownZ);
Vector3 forwardDirAfterRollAndPitch = rollAndPitchRotation * Vector3.forward;
Vector3 upDirAfterRollAndPitch = upDirEnd; // unnecessary but here for clarity

float determinedY = Vector3.SignedAngle(forwardDirAfterRollAndPitch, forwardDirEnd, upDirAfterRollAndPitch );
// Normalizing determinedY
determinedY = (determinedY + 360f) % 360f;

Vector3 eulers = new Vector3(determinedX, determinedY, knownZ); 

To ensure that the given quaternion can be made with the given component, you could check if the axes given to SignedAngle actually can rotate the input vector to the target vector, or you can just compare the calculated eulers and the given quaternion:

Quaternion fromEuler = Quaternion.Euler(eulerAngles);

if (fromEuler==desiredRotation) 
{
    // use eulerAngles here
}
else 
{
    // component and quaternion incompatible 
}

Hopefully that helps.

0
votes

I'm not quite sure I understand your question correctly, but the euler angles just represent the angles of 3 rotations applied around the 3 axis in a specific order, right? So why would you normalize it by adding 180 everywhere? You should bring each angle individually into the range 0-360 by modulo-ing them.

Your question seems to imply that you can obtain any orientation by only rotating around two axis instead of three... is that what you are trying to achieve? Using quaternions could possibly help you, in fact an orientation can be defined with just 4 scalar values: an axis and an angle