I am moving a specific node (a 40x.40y.1z cube) directly in front of the flyby camera, then facing it at the camera - and I have a question about rotating the node using Quaternion.opposite(). I can edit a few screenshots in later if needed, but I think I’m probably not understanding something basic about node rotation - that will hopefully be obvious to someone more 3d-math-savvy than myself.

Here is the code I’m using to get the camera location/direction, create the new node location, then get the rotation quaternion from the camera.

[java]
Vector3f location = camera.getLocation();
Vector3f direction = camera.getDirection().normalizeLocal();

final Vector3f snapPoint = location.add( direction.mult( 160 ) );
final Quaternion camRotation = camera.getRotation();
[/java]

Then the code to move the node and rotate it to face the camera (called from the jme thread).

If I move backward (+z) and/or strafe right/left (+/- x), the translation/rotation makes sense on the moved node and it is lined up properly. As in, the camera is looking at the center of the cube, and cube edges are aligned with the view frustum.

However, if I move through all three dimensions (like backward, up, and to the right) and then move the node, the cube still moves to the snap point and is centered - but is skewed and not aligned with the frustum.

I noticed also if I use just the camRotation instead of camRotation.opposite(), the cube aligns correctly no matter where I move (the result is the camera looking at the back of the node, obviously).

I’m thinking I have to “flip” the quaternion around the axis the camera is looking or something like that?

The Quaternion.opposite() method feels a little strange to me. It may be that it points in the “exact opposite direction” but it’s unclear what happens to the other axes in this repointing.

If you want to rotate 180 degrees then the best way might be to rotate 180 degrees. Take the camera’s rotation and multiply it by a quaternion representing a 180 degree rotation about the y axis.

Simplest and clearest:
Quaternion flip = new Quaternion().fromAngles(0, FastMath.PI, 0);

…nice thing is you could keep that around as a constant.

I can never confidently remember if it’s flip.mult(rotation) or rotation.mult(flip) without trying it. And it matters. I don’t have my own source code in front of me at the moment or I’d check.

Excellent, thanks heaps - works like a charm - rotation.mult( flip ).

Unfortunately, now I’m stuck on why it works.

Say I start by looking at the node where it’s initially added to the scene (0x, 0y,-100z). Then I pan straight down with the camera so I’m looking directly at -y and move the node - it still works. The node is technically moving and being rotated around the X axis to face the camera, right?

Quaternion multiplies are cumulative. So in a sense you are saying, first rotate like the camera and then rotate around the current (rotated) y-axis 180 degrees. rotation.mult(flip)

Just in case it wasn’t clear:

new Quaternion().fromAngles(0, FastMath.PI, 0)

…is rotating by PI around the y-axis. PI = 180 degrees.

If you then wanted it to be tipped down a little you could multiply again by:
new Quaternion().fromAngles(FastMath.QUARTER_PI/3, 0, 0)
…which is rotating around the x-axis by 15 degrees.

All taken together the cumulative rotation would be:
-whatever the camera rotation is
-then rotated 180 degrees around the local (rotated) y axis
-then rotated 15 degrees around the local (rotated) x axis
…and so on.

Each time you multiply a new quaternion into the chain, it is relative to all of the rotations up to that point.

Well, important safety note… when I say “local” above, I’m referring to coordinate spaces and not to the “local” as used in things like Vector3f.addLocal().

Though it kind of is the same thing as Spatial.setLocalRotation().