Sign in to follow this  
drb2k2

Damn dirty quaternions

Recommended Posts

Hi all, Yes i've had a look through previous posts. The problem is most of them seem to be dealing with quaternion cameras. OK now thats out the way let me explain the problem Basically I have a global axis XYZ which is tied in to the camera rotation, so for the moment lets pretend that it never changes and Y is always up, X off to the right I want to rotate objects around this axis. I have some numeric spinners to set the rotation value, so to rotate 90 degrees around the y axis just pop 90 into the y box. So far all is good. BUT, if you rotate 90 degress around the X axis, then try and rotate around the Z axis, it turns on the Y axis instead. Now I realize that this probably has something to do with an axis shifting with the model, That would be fine if all the axis did that. The y rotation spinner however will always spin around the correct axis. This means that if you rotate an object 90 degrees on the X axis, the Z rotation is now exactly the same as the Y rotation. I hope i've explained whats happening ok. Basically each object has a rotation vector. To rotate around the Y axis just add 1 to the Y value etc. The rendering part is as follows.
Dim qRot As Microsoft.DirectX.Quaternion
            Dim RadianRot As Microsoft.DirectX.Quaternion

            RadianRot.X = System.Math.PI * Me.ObjectDetailsList(Me.WhichObj).Rotation.x / 180
            RadianRot.Y = System.Math.PI * Me.ObjectDetailsList(Me.WhichObj).Rotation.Y / 180
            RadianRot.Z = System.Math.PI * Me.ObjectDetailsList(Me.WhichObj).Rotation.Z / 180



            qRot = Microsoft.DirectX.Quaternion.RotationYawPitchRoll(RadianRot.Y, RadianRot.X, RadianRot.Z)




            Dim RotMatrix As Microsoft.DirectX.Matrix = Matrix.Identity
            'might use this later for object positional
            Dim Cent As Microsoft.DirectX.Vector3
            Cent = New Microsoft.DirectX.Vector3(0, 0, 0)
            RotMatrix.AffineTransformation(1, Cent, qRot, New Microsoft.DirectX.Vector3(0, 0, 0))

           
// tried this and it is exactly the same //'RotMatrix.Multiply(Matrix.RotationX(Geometry.DegreeToRadian(Me.ObjectDetailsList(Me.WhichObj).Rotation.X)))
            //'RotMatrix.Multiply(Matrix.RotationY(Geometry.DegreeToRadian(Me.ObjectDetailsList(Me.WhichObj).Rotation.Y)))
            //'RotMatrix.Multiply(Matrix.RotationZ(Geometry.DegreeToRadian(Me.ObjectDetailsList(Me.WhichObj).Rotation.Z)))
            Me.device.Transform.World = Matrix.Multiply(RotMatrix, Me.device.Transform.World)
            Me.device.RenderState.Lighting = True
            device.SetStreamSource(0, Me.ModelVertexBuffer, 0)
            device.VertexFormat = CustomVertex.PositionNormal.Format
            device.DrawPrimitives(PrimitiveType.TriangleList, 0, Me.FacetCount)

If anyone can help or point me in the right direction I would be very grateful. Cheers DRB2K2

Share this post


Link to post
Share on other sites
im not sure if it makes a difference, but try constructing the quaternions seperatly from the rotationvalues, then combine them by multiplication into one.

Share this post


Link to post
Share on other sites
oh wait i think i got it.

you should accumulate the rotation in the quaternion. it seems like right now youre accumulating in euler angles, then convert those to quats. that way you might aswell not use a quat.

Share this post


Link to post
Share on other sites
hmmmmmmmm not too sure I see what you're getting at there. The vector3 structure is only used as a holding place for the rotation angle.

Do you mean to simply change this into a quaternion structure instead?
If thats the case then I don't think there'll be a difference.

Thanks for the suggestion though, keep em coming.

Cheers
DRB2k2

Share this post


Link to post
Share on other sites
Ok have cracked it
The rendering part was fine, what was wrong was the bit where I was calculating the rotation.
Before if I wanted a 90 rotation on the Z axis I would just put
Rot.Z = 90

Now though I've done this.

Dim temp As Microsoft.DirectX.Vector3 = New Microsoft.DirectX.Vector3(Me.NumericUpDown_RotX.Value, Me.NumericUpDown_RotY.Value, Me.NumericUpDown_RotZ.Value)
Dim test As Microsoft.DirectX.Vector3 = New Microsoft.DirectX.Vector3(0, 0, 1)
test.TransformCoordinate(Me.GlobalMatrix)

Dim mat As Matrix = Matrix.Identity
mat.RotationAxis(test, Me.NumericUpDown_RotZ.Value)
temp.TransformCoordinate(mat)
Me.ObjectDetailsList(Me.WhichObj).Rotation = temp

Basically we know that we want to rotate on the axis 0,0,1 for a z rotation.
This is dependent on the world transform so me.GlobalMatrix is simply device.transform.world

we then rotate around the transformed Z axis by the amount held in the rotation spinners e.g. 90 degrees
Then transform the entire rotation amount by these
et voila it all works
for the moment

Cheers
DRB2k2

Share this post


Link to post
Share on other sites
damn,
well it nearly works, just now the X axis always changes with the model

RadianRot.X = System.Math.PI * Me.ObjectDetailsList(Me.WhichObj).Rotation.x / 180
RadianRot.Y = System.Math.PI * Me.ObjectDetailsList(Me.WhichObj).Rotation.Y / 180
RadianRot.Z = System.Math.PI * Me.ObjectDetailsList(Me.WhichObj).Rotation.Z / 180


'qRot = Microsoft.DirectX.Quaternion.RotationYawPitchRoll(RadianRot.Y, RadianRot.X, RadianRot.Z)
Dim qX, qY, qZ As Quaternion
qX = Quaternion.RotationAxis(New Microsoft.DirectX.Vector3(1, 0, 0), RadianRot.X)
qY = Quaternion.RotationAxis(New Microsoft.DirectX.Vector3(0, 1, 0), RadianRot.Y)
qZ = Quaternion.RotationAxis(New Microsoft.DirectX.Vector3(0, 0, 1), RadianRot.Z)

'multiplication not communative causing rotation problems here
qRot = Quaternion.Multiply(qX, qY)
qRot.Multiply(qZ)




If I change around the multiplication order whichever one is done first changes its axis and ends up being the same axis as the last.

hmmmmmmmm is there a better way to generate a rotation matrix I wonder.

Cheers
DRB2k2

Share this post


Link to post
Share on other sites
Quote:
Original post by drb2k2
If I change around the multiplication order whichever one is done first changes its axis and ends up being the same axis as the last.

i think the difference might be in post-or premulitplication.

try both of these, and see if there is a difference:

qRot = Quaternion.Multiply(qX, qY)
qRot = Quaternion.Multiply(qRot, qZ)
//or
qRot = Quaternion.Multiply(qX, qY)
qRot = Quaternion.Multiply(qZ, qRot)


if i recall correctly the difference between post and premultiplication is that either you do rotation a in coordinate system b, or rotation b along coordinate system a. then again im not sure. i should brush up on these things myself a bit...

Share this post


Link to post
Share on other sites
as about pre-multiply and post multiply.
if to transform points you use
Q*Point*~Q - based formula, then
A*B will do rotation same as if you rotate first by B then by A.
That is, if i want to rotate camera around camera's x axis, i should rotate after i get point into camera space.
That is, i should use
QuaternionThatRotatesAroundXAxis*CameraQuaternion;
(then, result is supposed to be used for transform like Q*Point*~Q)

If i want to rotate around world's x axis i must use
CameraQuaternion*QuaternionThatRotatesAroundXAxis;
- i first rotate around world, then rotate by camera.

Some people store inverse of camera's quaternion instead of camera's quaternion itself. I myself do that, i have unified coordinate system class (instead of camera class) with method GetTransformTo and GetTransformFrom (returning 4x4 matrix ready for OGL). I use GetTransformTo for camera and GetTransformFrom for skeletons/etc. Very handy, in fact.

Share this post


Link to post
Share on other sites
ahha,
I see what you mean
Have decided to settle for

RadianRot.X = System.Math.PI * Me.ObjectDetailsList(Me.WhichObj).Rotation.x / 180
RadianRot.Y = System.Math.PI * Me.ObjectDetailsList(Me.WhichObj).Rotation.Y / 180
RadianRot.Z = System.Math.PI * Me.ObjectDetailsList(Me.WhichObj).Rotation.Z / 180

Dim matX, matY, matZ As Matrix
matX = Matrix.RotationX(RadianRot.X)
matY = Matrix.RotationY(RadianRot.Y)
matZ = Matrix.RotationZ(RadianRot.Z)

RotMatrix = Matrix.Multiply(matX, matY)
RotMatrix = Matrix.Multiply(RotMatrix, matZ)

RotMatrix = Matrix.Multiply(RotMatrix, Me.device.Transform.World)


Still not 100% on it though, thanks guys for your help especially Eelco
Much obliged

Cheers
DRB2k2

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Could it be that the product of tow quaternion is different than the product of two matrices.

q0 * q1 != r0 * r1

I believe this can be and was proof on another thread

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Could it be that the product of tow quaternion is different than the product of two matrices.

q0 * q1 != r0 * r1

I believe this can be and was proof on another thread

Don't sure what you mean.
I tested my quaternion lib by checking that
quaternion_to_matrix(q1)*quaternion_to_matrix(q2)
is nearly equal(except for roundoff errors) to
quaternion_to_matrix(q1*q1)
Though, if you use different convention that is IMHO confusing, it might be equal to
quaternion_to_matrix(q2*q1)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this