Making use of quaternions

Started by
4 comments, last by Norman Barrows 11 years ago

At the moment I'm rotating an object about its local yaw, pitch and roll axes using matrices as follows:

    D3DXMATRIX matYaw; D3DXMatrixRotationAxis(&matYaw, &up, OrientationDelta.x); //Build a yaw rotation axis

    D3DXVec3TransformCoord(&forward, &forward, &matYaw); D3DXVec3TransformCoord(&right, &right, &matYaw); //Apply the yaw transformation

    D3DXMATRIX matPitch; D3DXMatrixRotationAxis(&matPitch, &right, OrientationDelta.y); //Build a pitch rotation axis

    D3DXVec3TransformCoord(&forward, &forward, &matPitch); D3DXVec3TransformCoord(&up, &up, &matPitch); //Apply the pitch transformation

    D3DXMATRIX matRoll; D3DXMatrixRotationAxis(&matRoll, &forward, OrientationDelta.z); //Build a roll rotation axis

    D3DXVec3TransformCoord(&right, &right, &matRoll); D3DXVec3TransformCoord(&up, &up, &matRoll); //Apply the roll transformation



    OrientationMatrix *= matPitch*matYaw*matRoll; //Adjust the orientation matrix

Here, I'm rotating incrementally about three local axis vectors: up, forward and right. I am doing a small amount of rotation per frame (a delta value rather than an actual value) because I need to rotate the up, forward and right vectors along with my object to ensure that they stay as local axes.

I'm interested in converting this to use quaternions so that I don't have to worry about reorthogonalising my three local axis vectors every frame by taking vector cross products, etc... but I can't see how I'd do it. Surely to ensure that the object continues to rotate about its local yaw, pitch and roll axes, I'll need to keep using my three vectors and also my rotation matrices like I have above?

Thanks for your help!

Advertisement

I'm interested in converting this to use quaternions so that I don't have to worry about reorthogonalising my three local axis vectors every frame by taking vector cross products, etc... but I can't see how I'd do it. Surely to ensure that the object continues to rotate about its local yaw, pitch and roll axes, I'll need to keep using my three vectors and also my rotation matrices like I have above?

Thanks for your help!

sorry dude, looks like its not happening.

i've been researching this myself.

see these recent threads...

http://www.gamedev.net/topic/640230-how-to-re-orthogonalise-vectors/

http://www.gamedev.net/topic/640889-pixel-perfect-local-rotations-and-quats-vs-mats/

in a nutshell, quats accumulate error less quickly, but still get whacked after a while.

even rolling your own long double or long long fixed point implementation of mats or quats will eventually get whacked due to cumulative incremental local rotation precision errors. but depending on how long the game runs, long long fixed point might do it without getting too whacked by the end.

i've decided to stick with mats and gram shmitt for the moment, and hope that induced drift can be lived with.

note that selection of axes when normalizing will determine where the drift shows up and which turns will be accurate.

if you preserve the forward vector and adjust the other two, roll will work, and yaw and pitch will drift.

if you preserve up, yaw should work pixel perfect, and pitch and roll will drift.

if you preserve right, pitch will work, and yaw and roll will drift.

in the past i've preserved forward, and lived with drifting pitch at high screen resolutions.

but its probably better to preserve up or right (your preference), so either yaw or pitch drifts a bit, but not both.

there this whole rats nest mess of what type of data structure to store orientation in, and how to rotate that orientation about local axes.

the graphics engine uses mats. orientation can be stored a number of ways (mat; quat; vector & roll; Eulers; fwd,up,right [i,j,k] vectors; etc). turning uses mat mul, quat mul, or rotation about arbitrary axis, and i think double or triple skew is another possible method. movement use direction vector. AI (mine at least) uses Euler angles.

rotation about an arbitrary axis may be a possibility. first time i got 3 degree rotational freedom working, i used fwd,up,right vectors, rotation about arbitrary axis formula, and gramm-shmitt. but given that i was using gram-shmitt there, a float implementation of arb axis still wouldn't cut it.

so, given this rats nest, i've decided for the moment to use mats for orientation. mat mul turns them easily (orientation = local_rotation * orientation), you can use gramm-shmitt to keep them orthogonal: normalize(&orientation). the graphics engine can use the mat directly (world = scale * orientation * translation). the movement engine can use the 3rd column vector (forward vector) directly (x+=speed*fwd.x, y+=speed*fwd.y, etc). and euler angles can be easily extracted for use by AI, etc. code for extracting eulers from mat is posted in the above mentioned threads.

note also that your turn rate, if very small, will induce error faster.

overhead of normalize() doesn't seem to be an issue in this day and age, even normalizing after every incremental rotation.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

Hey - yeah, I saw your post in my other topic! Thanks for the reply. The Gramm-Schmidt idea looks good - do I have to make my own function to implement that, or does D3D do it somehow? I guess it wouldn't be too hard to make a function form something like this:

http://www.gamedev.net/topic/48987-gram-schmidt-reorthogonalization-routine/

Thanks again!

here's the normalize routine i posted in the first thread mentioned above...

void normalize()
{
/*
Column1=Normalized(CrossProduct(Column2,Column3));
Column2=Normalized(CrossProduct(Column3,Column1));
Column3=Normalized(Column3);
Prot is global player's rotation matix
*/
D3DXVECTOR3 v1,v2,v3, // 3 original axes
v4,v5,v6; // 3 ortho normal axes
v1.x=Prot._11;
v1.y=Prot._21;
v1.z=Prot._31;
v2.x=Prot._12;
v2.y=Prot._22;
v2.z=Prot._32;
v3.x=Prot._13;
v3.y=Prot._23;
v3.z=Prot._33;
D3DXVec3Cross(&v4,&v2,&v3);
D3DXVec3Normalize(&v4,&v4);
D3DXVec3Cross(&v5,&v3,&v4);
D3DXVec3Normalize(&v5,&v5);
D3DXVec3Normalize(&v6,&v3);
Prot._11=v4.x;
Prot._21=v4.y;
Prot._31=v4.z;
Prot._12=v5.x;
Prot._22=v5.y;
Prot._32=v5.z;
Prot._13=v6.x;
Prot._23=v6.y;
Prot._33=v6.z;
}
note that this version keeps the forward (z) vector fixed, and adjusts up and right vectors.
for fixed y (up local axis):
y is column v2.
so its v1 = norm(v2 x v3), v3=norm(v1 x v2), v2=norm(v2).
for fixed x (right local axis):
x is column v1.
so its v2 = norm(v1 x v3), v3=norm(v1 x v2), v1=norm(v1).
you should be able to cut and paste this directly into any D3D app and pass a D3DXMATRIX directly to it.
consider it a freebie sample from Rockland Software Productions' Z game library. <g>
note also that it actually uses a global player orientation matrix "Prot". you may want to change this to use a matrix passed by reference.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

I already do something similar - I hold three vectors called up, right and forward, and I renormalise and cross them every frame to make sure they stay orthonormal. I keep the up vector constant though. I think it's the same. Thanks anyway!

now i'm checking into the QR decomposition mentioned in the thread you mentioned. but it may be overkill. we're using gram-schmidt to "fix up" skewed (imprecise) axes. since the axes are already imprecise, i don't see a hi-rez normalize making things any better, possibly not worse, but not any better. unless some of the drift is caused by the inaccuracy of gram-schmidt. yet another thing to test i guess.

the full local ortho-normal basis mentioned in that thread is similar to the fwd, up, and right axes that you use, and i've used in the past. most likely combined with rotation about an arbitrary axis. and using the rotation about axis formulas: x'= x*cos(theta) + y*sin(theta) kind thing. i think i recognize the add and mul counts (2 muls 4 adds per point, per axis, was it? been a long time since i did it that way). actually its the "5 2d rotations" in that thread that tipped me off. this is how i actually did it.

you see, i was working on a starship flight sim. i was about to licence rend386. then MS bought the company, and took it off the market. they then spent a year turning it into directx v1.0. so during that time, i was forced to write my own perspective correct texture mapped poly engine (my own version of directx). it didn't use matrices, just 2d rotations. same difference, but matrices do all the math at once, instead of one axis at a time.

but it looks like the slickest implementation will be:

orientation = local_rotation * orientation

normalize(orientation)

when you get it up and running, splash some bogies for me!

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

This topic is closed to new replies.

Advertisement