Turning wrong direction around Z axis after flipping on Y axis

Here is a visualization of the problem:

The quaternion in my code named ‘turn’ produces different turns if the quaternion ‘flip’ is applied to the object. My quaternion understanding is pretty weak. Why does applying the ‘flip’ rotation affect how ‘turn’ rotates?

Here is my code:

private static Quaternion flip = new Quaternion().fromAngleAxis(FastMath.DEG_TO_RAD * 180, new Vector3f(0, 1, 0));
private static Quaternion turn = new Quaternion().fromAngleAxis(-FastMath.DEG_TO_RAD * 90, new Vector3f(0, 0, 1));
private static Quaternion unturn = new Quaternion().fromAngleAxis(FastMath.DEG_TO_RAD * 90, new Vector3f(0, 0, 1));

public static void turn(Spatial spatial, int turnAmt) {
    if (turnAmt == 0)
        return;
	
    Quaternion rotation = turn;
    if (turnAmt < 0)
        rotation = unturn;
	
    for (int i = 0; i < Math.abs(turnAmt); i++) {
        spatial.rotate(rotation);
    }
}

public static void flip(Spatial spatial) {
    spatial.rotate(flip);
}

Rotations are relative to the last rotation.
A x B… rotate A then rotate B

B x A rotate B then rotate A

These are different. So if you flip the card upside down it’s now facing the other way and rotations will be reversed.

…or you could premultiply.

There seems to be a commonality between this and my other post where the current rotational orientation of the object is effecting results in ways I don’t yet understand. Is there a way to specify a current orientation independent rotation? Using a quaternion or through some other means? I imagine one solution based on what you said would be to not accumulate rotations as they come in using rotate() but store them in memory and only apply the rotation to the object in order of axis Z, Y, X all at once.

Usually, it’s just a matter of premutiplying versus post multiplying.

Quaternion someTurn…

Quaternion turnRelativeToObject = object.getLocalRotation().mult(someTurn);
object.setLocalRotation(turnRelativeToObjecT);

Quaternion turnRelativeToWorld = someTurn.mult(object.getLocalRotation());
object.setLocalRotation(turnRelativeToWorld);

I really appreciate your time and can’t thank you enough. I read about 10 more threads and did some more homework on 3d rotations. Tried to understand your solution as best I could and finally parsed out the relevant part. That turnRelativeToWorld was the ticket.

Here is the code:

private static Quaternion flip = new Quaternion().fromAngleAxis(FastMath.DEG_TO_RAD * 180, Vector3f.UNIT_Y);
private static Quaternion turn = new Quaternion().fromAngleAxis(-FastMath.DEG_TO_RAD * 90, Vector3f.UNIT_Z);
private static Quaternion unturn = new Quaternion().fromAngleAxis(FastMath.DEG_TO_RAD * 90, Vector3f.UNIT_Z);

public static void turn(Spatial spatial, int turnAmt) {
	if (turnAmt == 0)
		return;
	
	Quaternion rotation = turn;
	if (turnAmt < 0)
		rotation = unturn;
	
	for (int i = 0; i < Math.abs(turnAmt); i++) {
		Quaternion turnRelativeToWorld = rotation.mult(spatial.getLocalRotation());
		spatial.setLocalRotation(turnRelativeToWorld);
	}
}

public static void flip(Spatial spatial) {
	Quaternion turnRelativeToWorld = flip.mult(spatial.getLocalRotation());
	spatial.setLocalRotation(turnRelativeToWorld);
}

Here is the proof: