Damn dirty quaternions

Started by
11 comments, last by GameDev.net 19 years, 2 months ago
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
Advertisement
im not sure if it makes a difference, but try constructing the quaternions seperatly from the rotationvalues, then combine them by multiplication into one.
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.
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
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
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
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...
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.
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
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

This topic is closed to new replies.

Advertisement