- Home /
Other
Quaternion.Euler rotations don't add up
My team has been trying for a day to get rotations to work on a vector. We read Quaternions can easily be multiplied with a vector to get the desired rotated vector. However, there seems to be something we don't quite understand. For example we'd expect the following code to rotate vector x to its original orientation, since each rotation axis adds up to a rotation of 360 degrees.
Vector3 x_a = new Vector(13,4,5); // Just an example
Vector3 x_b = Quaternion.Euler(new Vector(180,300,350)) * x_a;
Vector3 x_c = Quaternion.Euler(new Vector(180, 60, 10)) * x_b;
However, x_c != x_a.
Can someone explain the intended use of Quaternion.Euler to us? (How) could this example be changed to make x_c equal x_a?
Rotations don't "commute". That means the result depends on the order in which you apply them. To get the idea intuitively, put your hand flat on the table, and rotate it: (1) a quarter-turn around the world's Y axis; (2) a quarter-turn around the world's Z axis; (3) an opposite quarter-turn around the world's Y; (4) an opposite quarter-turn around the world's Z axis (not your hand's axis! always the world's). This is the result of Quaternion.Euler(0, 90, 90) * Quaternion.Euler(0, -90, -90). It's not Quaternion.identity at all.
Thanks @Ar$$anonymous$$Rigo for your reply to this years old question. From the top of my now slightly more educated head: would a solution be to rotate the second rotation vector (180, 60, 10) , let's call it v2, along with the original vector x, yielding x_b and v2_b, and then applying the Quaternion of v2_b to x_b?
"Rotation vectors" are not really a thing. The vector (180, 60, 10) should only be understood as the convenient way to write a product of three different rotations. Quaternion.Euler() is a rotation around the Z axis then one around the X axis then one around the Y axis, in this specific order. Let's call each of these rotations qz, qx and qy: then the rotation is q = qy qx qz. The inverse of qx, inv(qx), is clearly the rotation along the same X axis with the opposite angle. The same for inv(qy) and inv(qz). Then inv(q) = inv(qz) inv(qx) inv(qy). Notice that the order is reversed. That means that if you want to express inv(q) as Quaternion.Euler(...), you need to find three angles, but these angles are not simply the opposites of the original three angles---because that would give the quaternion inv(qy) inv(qx) inv(qz) ins$$anonymous$$d of inv(qz) inv(qx) inv(qy). I hope it makes sense to you! The general rule of thumb is that Quaternion.Euler() is good only in some situations but not others.
Not really my question, but a good explanation nonetheless. :)
Also you can't multiply a quaternion by a scalar (float) and expect the result to be a meaningful rotation quaternion. Quaternion by itself is something like a higher order complex number. Not every quaternion describes a rotation. Quaternion in the context can be understood as a simplified transform matrix, that would otherwise contain many duplicit values (using a transform matrix is therefore less efficient)
Perhaps you could first try to understand by yourself, how can a rotation in 2D be described by a single normalized complex number, and how those add up when multiplying them. It's much simpler to grasp than quaternion.
Hi! Thanks for your reply. Please bear in $$anonymous$$d that this topic is over six years old.
Answer by meat5000 · Nov 20, 2013 at 07:01 PM
The rotations in Q-Euler are around the world axes I believe (in the order z, x, y). Work through with this on paper and you'll probably find it's correct. On paper treat Vector x as a point in space.
Place a cube at the point in space determined by your x vector. Apply the two rotations you created to the cube via script and you will see the same results.
Place the following onto a script and place it on a cube with position 13,4,5. It simply performs each rotation one axis at a time so you can see whats going on a bit better.
#pragma strict
var timer : float = 0.0;
var stage1 : boolean = true;
var stage2 : boolean = true;
var stage3 : boolean = true;
var stage4 : boolean = true;
var stage5 : boolean = true;
var stage6 : boolean = true;
function Update()
{
timer += Time.deltaTime;
if (timer >= 3.0 && stage1)
{
transform.position = Quaternion.Euler(0,0,350) * transform.position;
stage1 = false;
}
if (timer >= 6.0 && stage2)
{
transform.position = Quaternion.Euler(180,0,0) * transform.position;
stage2 = false;
}
if (timer >= 9.0 && stage3)
{
transform.position = Quaternion.Euler(0,300,0) * transform.position;
stage3 = false;
}
if (timer >= 12.0 && stage4)
{
transform.position = Quaternion.Euler(0,0,10) * transform.position;
stage4 = false;
}
if (timer >= 15.0 && stage5)
{
transform.position = Quaternion.Euler(180,0,0) * transform.position;
stage5 = false;
}
if (timer >= 18.0 && stage6)
{
transform.position = Quaternion.Euler(0,60,0) * transform.position;
stage6 = false;
}
}
Hello meat5000, thanks for your reply. If quaternions are meant to rotate around the world axes, some questions pop to my $$anonymous$$d. Do you $$anonymous$$d if I fire them at you? No matter what you turn in or around, shouldn't rotating 360 degrees in total always rotate back to the original state? What do you think I do not get here? And to solve my problem: I'm simply tring to rotate the direction of a vector, not a point in space. How would you suggest I do that if not like this? Thanks a lot for your time.
Quaternion.Euler rotates around the World axes. If you are trying to rotate the object itself apply your quaternion to transform.rotation ins$$anonymous$$d :)
$$anonymous$$anipulating Vectors is a little more complex and often requires the use of matrices. As you have seen, your first rotation performs three separate rotations and each one changes the position of the object in world space. They are simply not commutable like straight forward algebra. When you come to perform your second (three) rotation(s) the object is not in the place you expected to begin :)
A circle always requires 2 axes. Perfor$$anonymous$$g a circular motion on an object (rotating in a circle around an axis) will always change the position in two axis. And this is where you misconception applies. The only way to not affect 2 axes is to move in a straight line parallel to an axis, ofc.
In Unity a Vector and a point in space are basically one and the same. What makes your Point in space equal a Vector is that it's relative to 0,0,0, which is what gives it a direction. Of course, this is a generalisation.
I really should ask...what exactly is it that you are trying to do? :D
Currently I'm just trying to rotate a vector. For example (0,1,0) turned 90 degrees (clockwise) around the z-axis would give (1,0,0). Turning it 90 degrees back would again give (0,1,0) and turning that 360 degrees in any way would also give (0,1,0).
That is really all I want to get to work now, but if you're interested what I'm using it for: the reason I want to rotate a vector is that I'd like to store a point in space, relative to a specific mobile object. For this I calculate the distance between the object and the point (at a certain moment in time). I store this distance, which is basically a vector from the object to the point I have in $$anonymous$$d. Because I have to take into account the rotation of the object at that moment in time, I want to "undo" that rotation on the vector I store. So I want the vector that would point from object to my point in space, if the object would have a rotation of 0,0,0. This way I can find my point in any frame, simply by applying the rotation of the object at that time to the vector stored and adding that rotated vector to the position of the object.
The steps of "undoing" and later reapplying a rotation is where I thought to use Quaternions. But it seems I still don't get what they actually do when multiplied to a vector. I would expect that turning 360 degrees around any axis would leave a vector untouched. I haven't found anything to suggest Quaternions do not work like this, but it seems they don't. So that leaves me with these questions:
Why don't quaternion rotations add up? ($$anonymous$$eaning 360 degrees would make a full circle.)
What ARE quaternions meant for if not for rotating things in the way I expect and think is intuitive?
Can I still use quaternions for my purpose or is that not what they are for and do I need something else and what would that be?