Transfer roll from one quaternion to another

So this sounds like a very simple problem, but I can’t get it to work right for the life of me.

If you have a quaternion with a certain rotation (also some values on X and Y axis)

Quaternion a;

and would like to replicate ONLY the rotation around the Z axis to another one without changing the other two axis on the b quaternion at all.

Quaternion b;

I’ve tried a load of things like these:

float z = a.toAngleAxis(new Vector3f(0,0,1));		
Quaternion q = new Quaternion();
q.fromAngleAxis(z,Vector3f.UNIT_Z);		
b.multLocal(q);
//worked until you get past 240 degrees, then it just does weird things

and

float[] axis = new float[3];
a.toAngles(axis);
axis[0] = 0;
axis[1] = 0;		
Quaternion q = new Quaternion();
q.fromAngles(axis);		
b.multLocal(q);
//z axis is limited to +-90 so it breaks everything

Apparently fromAngleAxis can’t be trusted so obviously that didn’t work. I’d really like to avoid using euler angles but I don’t know how would one do this with only vector3fs and quaternions.

Also I know that toAngleAxis doesn’t work exactly the way I used it, but using the z value of the store vector doesn’t work either.

I’m all out of ideas.

You should tell us why you are doing what you are trying to do… maybe we can help then. Like, what is it that you are really trying to do.

Quaternions are compact representations so they don’t have the angles you want.

That doesn’t mean there isn’t a way to do your ultimate goal if we knew what it was.

Exactly what I said. I need to transfer the roll from a ship’s rotation to the camera’s rotation. I suppose I could do it with vectors somehow, and that’s why I’m here.

Still the quaternion data is all I’m working from.

Where did you say that? I read it again and still missed it. I only saw “Quaternion” and “Quaternion”.

And still the part I have trouble understanding is what “roll” means when the view vectors aren’t aligned. If the camera is looking straight down on the ship then what’s roll mean?

Without knowing what you are actually doing and how varied the camera rotation can be from the ship’s rotation and at what point it doesn’t make sense anymore…

One approach would be to get the camera’s rotation relative to the ships instead of in world space.

Something like:
Quaternion localView = ship.getWorldRotation().inverse().mult(cam.getRotation());

…then 0 out the z axis rotation.
float[] angles = localView.toAngles(null);
unrolledLocalView = new Quaternion().fromAngles(angles);

…then bring it back into world space:
cam.setRotation(ship.getWorldRotation().mult(unrolledLocalView);

Something like that.

It’s always the ship’s Z axis, as the camera trails behind it. Both quaternions are alligned along the Z axis at about 80%-100% but I can’t count on that. [quote=“pspeed, post:5, topic:36410”]
Something like:Quaternion localView = ship.getWorldRotation().inverse().mult(cam.getRotation());

…then 0 out the z axis rotation.float angles = localView.toAngles(null);unrolledLocalView = new Quaternion().fromAngles(angles);

…then bring it back into world space:cam.setRotation(ship.getWorldRotation().mult(unrolledLocalView);
[/quote]
Hey that sounds promising, I’ll test it out.

It still has the ±90 range error problem due to toAngles, but it does work consistently in all directions so at least that’s good. I doubt there’s a way around the deficiencies of toAngles and toAngleAxis though.

Thanks for trying.

I feel like this is a lost cause but in case it helps, here’s an extended explanation of what I’m doing. I’ll try to keep it down to a slice of the system since there’s no point explaining the entire system.

Let’s say you have a box in the scene like the yellow wireframes below. They may rotate a bit on the X and Y axis, but the camera should ignore that and only track the Z axis rotation, aka roll for the box.

What the camera should do is rotate itself to allign with the roll of the object while keeping its original orientation on the other two axis.

So regardless of the cameras current rotation and position, do you want it to rotate “on the spot”, only around the Z access, exactly the same as the cube (or w/e) in question?

Yep, that’s right. If I have that I can transfrom it to the required space/rotation with ease.

I essentially only need one float, the Z-rotation of the box.

I reckon that the z axis of the camera must be equal to the green z axis in the picture above. Let’s call the axes of the camera X, Y, Z and the axes of the object in question x, y, z. The reference axes are the colored ones in the picture above, which we call x’, y’ and z’. These should be known in order to transform x,y,z correctly and maybe they are even the unit axes. But in any case Z=z’.

To build a Cartesian frame like this you have to project the x and y axes into reference frame. This can be done using dot products.
X=dot(x,x’)+dot(x,y’) and normalize X!
Y=dot(y,x’)+dot(y,y’) and normalize Y!
Z is trivial.

I remember something like quaternion.fromAxes(X,Y, Z).

No matter what I approach you use, I think you will have problems when the rotation of Z is more than 90 degrees because it’s then really difficult for math to tell what you want to do and anyway the local space quaternion may have interpreted that rotation in a non-z rotation way.

For the center box which is alligned with the reference, yes. But if you look at the four outlying boxes and their supposed Z rotation column you can see that it’s not directly alligned with the camera’s Z or the reference one.

Still I think I might be able to neglect this for the most part.

That’s…great, but I think I already have the local frame by doing what @pspeed wrote:


Okay, but how about going about this with vectors? I had this idea about getting the Y rotation columns and then somehow negating the X and Y axis, and finally just get the angle between the vectors. That should in theory work right? Doesn’t give me any indication if it’s a left or right roll though.

Do you use ChaseCamera? If you do,you’ll surely have issues when the roll is higher than 90 degrees. You’ll have to rewrite that class to adapt on what you’re trying to do.

I use a heavily modified version of ChaseCamera that works pretty much nothing like the original and is already adapted and lined up, the angle is the only missing piece. Thanks for the concern though. :slight_smile:

1 Like

Thinking of it a different way… what exactly are those yellow boxes representing?

Like, can their ‘not pointing the same direction as the middle’ be calculated relative to the middle in the first place so that there is no issue? How is their angle determined now?

1 Like

Look if you want to know exactly how this looks, then here you go. There’s a certain area in the middle of the screen where the camera shouldn’t move to allow for precision aiming, but rolling should still be possible.

The rotation is determined from the reticle’s position projected into the scene and the ship tries to allign itself towards it. The x and y angle can be accesed from toAngles reliably.

Now this gave me an idea, why not try to extract the other two angles and then multiply the inverse quaternion with the original? This would leave only the Z angle…except that stuff doesn’t work that way because we can’t have nice things. :confused:

I ended up with a weirder version of the toAngles Z component, except that it slows down then it starts to get close to ±90 deg and jitters when it gets there. sigh

You might try using look at with the existing look vector but the up vector from the ship’s local space.

2 Likes

Huh, that might actually work.

Bravo @pspeed. Next time I’ll give you the imgur gallery first. :smile: