Advertisement

Help with Quaternion rotation (6DOF)

Started by February 28, 2016 04:56 PM
46 comments, last by SBD 8 years, 11 months ago

(donning flame retardant gear...)

1. odds are your graphics library uses MATs not quats internally . so you have to covert to draw anyway (or it does it for you). so you might as well just use mats for everything. quats are preferred for lerping between two orientations, in almost all other cases, a MAT will do. MATs (eulers) are more intuitive to work with. When concatenating finite discrete rotations, Quats degenerate about half as fast as mats due to floating point error, but still must be re-ortho-normalized.

2. flight sims use local rotations, not global. you'll need the "rotation about an arbitrary axis" formula (IE angle-axis formula), not the normal (global) rotation formulas.

3. both mats and quats suffer from floating point error as you append small discrete rotations to your ship's orientation, this requires re-ortho-normalization to guarantee forward, up, and right remain mutually perpendicular and do not become skewed. Gauss' algo is used for mats. Quats have an analogous algo.

so orientation is stored in a mat (fwd, up, and right vectors), rot about arb axis is used to turn, and then you re-ortho-normalize. can also be done with quats, just less intuitive.

note that flight sims are about the only type of game that uses 6DOF and local rotations. so when you start asking about these things, you'll find 90% of gamedevs have no idea what you're talking about. so you'll get a lot of answers that apply to storing orientation and other such things when using global, not local rotations.

and now for the acid test:

once you've correctly implemented 6DOF and local rotations, you should be able to begin at any arbitrary orientation, do a 360 around any local axis, and come back to exactly the same pixel in front of you when you're done - no drift whatsoever. then you know you got it right.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

MATs (eulers)


I assume "MATs" means "matrices", since the rest of your post makes sense with that interpretation. However, matrices are not the same thing as "eulers", assuming by that you mean "Euler angles"; they are not even close. Whether he uses matrices or quaternions is completely irrelevant.

I am pretty sure you can apply "local rotations" by composing the rotations in a different order.
Advertisement

The easiest way to do this is to track an up, right and forward vector per ship.

On input just apply the delta rotation around each of these axes to the current rotation matrix/quat and recalculate the up, right and forward vectors.

You can extract the up, right, and forward vectors from a quaternion (or a matrix), by just rotating the matching basis vector by the quaternion/matrix.

Then build an angle-axis rotation about the vector, and concatenate as you are doing now.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

The easiest way to do this is to track an up, right and forward vector per ship.

On input just apply the delta rotation around each of these axes to the current rotation matrix/quat and recalculate the up, right and forward vectors.

You can extract the up, right, and forward vectors from a quaternion (or a matrix), by just rotating the matching basis vector by the quaternion/matrix.

Then build an angle-axis rotation about the vector, and concatenate as you are doing now.

So correct me if i am wrong but are you suggesting to keep 3 vectors (up being (0,1,0) right being (1,0,0) and forward being (0,0,1)) and then times these by the rotation of the ship after any rotation is done. Then use them as the axis of rotation when computing axis angle e.g. for yaw (or what was (0,1,0)) with the new up ?

The easiest way to do this is to track an up, right and forward vector per ship.

On input just apply the delta rotation around each of these axes to the current rotation matrix/quat and recalculate the up, right and forward vectors.

You can extract the up, right, and forward vectors from a quaternion (or a matrix), by just rotating the matching basis vector by the quaternion/matrix.

Then build an angle-axis rotation about the vector, and concatenate as you are doing now.

So correct me if i am wrong but are you suggesting to keep 3 vectors (up being (0,1,0) right being (1,0,0) and forward being (0,0,1)) and then times these by the rotation of the ship after any rotation is done. Then use them as the axis of rotation when computing axis angle e.g. for yaw (or what was (0,1,0)) with the new up ?

E.g. for a yaw action.

You'd multiply (0,1,0) by your current rotation matrix/quat then use this axis for you angle-axis delta transformation that you apply to your current rotation/quat.

You could keep track of each vector by applying the delta transform but that was more for verbosity/debugging purposes.

Advertisement


E.g. for a yaw action.

You'd multiply (0,1,0) by your current rotation matrix/quat then use this axis for you angle-axis delta transformation that you apply to your current rotation/quat.

Yep, exactly that. Yaw is a rotation about the local Y-axis of the quaternion.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

arr ok, i was going to say that i was still getting problems where the "roll" of the ship would still change even though i was just rotating by pitch and yaw (y and x axes) would this be fixed with local axes being used instead of global

@Alvaro

i was a bit confused in the end to when you said i should store the rotation angle for yaw pitch and roll (x y and z axes) and then create the quat.

I tried doing this with

glm::quat xrotation = glm::angleAxis((rotation.x),glm::vec3(1,0,0));

glm::quat yrotation = glm::angleAxis((rotation.y),glm::vec3(0,1,0));
glm::quat zrotation = glm::angleAxis((rotation.z),glm::vec3(0,0,1));
then I would reset the objects rotation by making it equal the following
currentrotation = zrotation * yrotation * xrotation ;
and to get the rotation i am still using the following

if(currentmouse.x < 540)
     {
       rotation.y += -(540 - currentmouse.x) * 0.0002f * deltaTs;
     }
     else if(currentmouse.x > 740)
     {
       rotation.y += -(540 - currentmouse.x) * 0.0002f * deltaTs;
     }
     else
     {
       rotation.y = 0;
     }
     if(currentmouse.y > 400)
     {
        rotation.x += (currentmouse.y - 400) * 0.0005f * deltaTs;
     }
     else if(currentmouse.y < 320)
     {
       rotation.x += -(320 - currentmouse.y) * 0.0005f * deltaTs;
     }
     else
     {
       rotation.x = 0;
     }
but i would still get unexpected rotations in say the z axes when I only rotated by y and x, is there something else i am missing here as the fix i posted

arr i seem to have got this working by doing

currentrotation = currentrotation * xrotation * yrotation;

was not resetting the current rotation

The order of multiplication is very important. If your ship is facing towards (0, 0, 1) and you think of (0, 1, 0) as "up", you should probably apply roll first (rotation around (0, 0, 1)), then pitch (rotation around (1, 0, 0)) and finally yaw (rotation around (0, 0, 1)).

I remember being confused by these things when I first played around with them. Take a toy plane and do the rotations with your hands so you understand what's going on.

Now, for a space combat game you might be better off not thinking of roll, pitch and yaw: That particular parametrization has special configurations where it behaves badly (look up gimbal lock), so you are probably better off with code like what you started with, where the state you keep is a rotation and you just compose new rotations with it. It also doesn't seem right that you only allow the ship to move in the direction it's pointing. [But of course game physics and real physics are not the same thing, so do whatever makes the game fun.]

This topic is closed to new replies.

Advertisement