I thought Quaternion.AngleAxis would create rotations that are perpendicular to the axis that you specify as parameter. But I didn’t get that behaviour.

I converted the resulting rotation to eulerAngles (in the Debug.Log statement), created a new object after every run of the script (all objects parented to the WORLD) and inserted the euler angles in the rotation fields of the object’s inspector.

The result can be seen here, with the rotation axis in orange:

What I had expected instead (warning: aligned manually, so not perfect!):

Where’s my faulty reasoning? What haven’t I understood about the way AngleAxis works?

So… Quaternions are not an orientation, they’re an amount of rotation. They’re like vectors for rotation.

This means that when you apply a Quaternion as the orientation of an object… really what you’re saying is “from the orientation of NO rotation, change this amount”.

So you must always consider what the object looks like when it origin rotation euler(0,0,0). I don’t know what your image looks like at that, because none of them are oriented at no rotation. But I’m willing to bet it’s the sphere end of the extruded rectoid pointing down a primary axes (probably x).

So now, do me a favor…

Take something long and cylindrical that can bend. A pipe cleaner for instance. Or a rigid copper wire. (or visualize this in your head)

Bend a 45 degree angle in it so you have a V.

Hold one end, and spin it it around itself.

Note how the end you’re not holding spins about… if all rotations were seen it’d appear like a cone.

This is exactly what you’re doing. Your object is oriented 45 degrees off the axis you want to rotate around. And as you apply angle in AngleAxis, you’re just picking a new position around that axis. You’re spinning it like the copper wire in your hand.

You can tell this by setting the rotation to:
Quaternion.AngleAxis(0f, axis)

Note there will be NO change. It’s still euler(0,0,0)

Now, because quaternions are ‘amounts’ of rotation, if you just calculated a quaternion that first oriented orthogonal (3d perpendicular) to the axes in question, like you desired in your image. And then multiplied the change around that axes, you’d get your result.

Something like this:

void Update()
{
var axis = Vector3.one.normalized;
//get the orientation that would point our forward axes down the rotational axes (1,1,1)
var orient = Quaternion.FromToRotation(Vector3.forward, axis);
//get a rotation based on time around (1,1,1)
var rotate = Quaternion.AngleAxis(Time.time * 5f, axis);
//rotate and orient
this.transform.rotation = rotate * orient;
}

This orients us orthogonal to the axes desired (in this I’m pointing the +z axes down (1,1,1)… change Vector3.forward to whatever axes you want to change it).

Then I calculate the rotation around it based on time, just to simulate it on Update for visualization.

Apply the calculated rotation as rotate * orient. Yes, the orient comes AFTER in the order of operations.

The way you can consider the order of operations of a quaternion is that the axes around which it says to rotate is relative to the rotation it’s getting multiplied onto.

So if we had said ‘orient * rotate’ we’d be pointing right down (1,1,1), but then telling it to rotate around it’s relative local (1,1,1)… which has now rotated to point a completely different direction.

Oh, I came back to point out something with the order of operations of quaternions that might help visualize it.

If we wanted to flip the order, this is what we’d do:

void Update()
{
var axis = Vector3.one.normalized;
//get the orientation that would point our forward axes down the rotational axes (1,1,1)
var orient = Quaternion.FromToRotation(Vector3.forward, axis);
//get a rotation based on time around (0,0,1)
var rotate = Quaternion.AngleAxis(Time.time * 5f, Vector3.forward);
//rotate and orient
this.transform.rotation = orient * rotate;
}

Note, we still say orient so our forward faces down (1,1,1).

But we create our rotation around the ‘forward’ axis.

Now when we say “orient * rotate”, we’re orienting so that forward points where we want, then we say and rotate around your forward. Because the forward is pointing (1,1,1), it therefore rotates around that.

@ lordofcut: Thanks so much for your detailed explanation. It definitely gave me a better understanding of Quaterions and the AngleAxis behaviour. I don’t want to say I understood all of it, but I made a step forward! Quaternions are not really the most intuitive thing I’ve come across in computer graphics…
I guess I will need to reread your explanation a few times to really grasp it all.