Quaternion Functions OK ?

Blitz3D Forums/Blitz3D Programming/Quaternion Functions OK ?

Ricky Smith(Posted 2003) [#1]
Just want to know if anyone has tried successfully to convert Blitz pitch,yaw and roll values to quaternions using either the Functions in the code archives or the many functions available on the internet.
I have tried a few and they all seem to return the w value ok but the x,y,z components are always mixed up (z=x,x=y,y=z) with the x and y values having reverse polarity.
Its not a major issue as I just adjust the values returned to the correct component part, but I was just wondering why this should be and is it because of the different coordinate types/standards ? e.g. Max inverts the y and z component but I would have thought that pitch ,yaw and roll were global.
I'm pretty sure I am using the functions correctly but you never know !


Wavey(Posted 2003) [#2]
They seem to work OK for me. How do you know what the x, y and z components should be?

If I remember correctly, there *is* a change in "handedness" of coordinate systems somewhere, but the code in the archives should compensate for this. There are examples of the quaternion code being used here: http://www.dscho.co.uk/blitz/tutorials/quaternions.shtml if you want to make sure you're using them correctly.


Ricky Smith(Posted 2003) [#3]

How do you know what the x, y and z components should be?



I'm using the returned quaternion values to write animation keys. When these keys are replayed then the animation has the correct amount values but on the wrong x,y,z axis. I have tested this extensively and compared the generated quaternion values using the functions in the archives with standard animation key values for identical frames and they are different.
Take an animated model -set the model to any frame using SetAnimTime()- convert the local pitch,yaw and roll values of each joint to a quaternion - the values returned are different to the animation key values for that frame - the components are mixed as explained above with the x and y component inverted - you may have to view the .b3d file as XML to view what the keys quaternion values should be.
As I said, its no big deal as I simply reallocate the value to the correct component and reverse polarity where needed.
However as you say it works for you then it could well be something else that I've overlooked.
Thanks for the reply - much appreciated !


Wavey(Posted 2003) [#4]
Sorry, I'm not sure what "standard key values" are - have these been generated outside of Blitz? If so, it might be that change in handedness I mentioned before that's causing the discrepancy.


Ricky Smith(Posted 2003) [#5]
The standard animation keys I am comparing against were generated in CharacterFX and exported as .b3d. These, of course, load fine and play the animation correctly.
Translating these key positions back to quats from the local pitch,yaw and roll values of each joint does return the same values but not in the right component except for w.
Its not just the function in the archives - I have created my own from C++ examples on the net and I get similar results.


Wavey(Posted 2003) [#6]
Ah, I think I see what might be going on - if the quats are in a b3d file, they'll have been generated by something else. I think there are different ways to calculate quaternions, and the method in the archives may not be the same as Blitz uses internally. So the QuatToEuler function should generally only be used on quats made by the EulerToQuat function, and vice versa.


Ricky Smith(Posted 2003) [#7]
That sounds logical - many thanks !


MattG(Posted 2003) [#8]
i have had many problems like this when trying to convert values from the GTA games , as this is how they store there objects , would you mind trying to help me out if i can sort some examples out

Matt


Ricky Smith(Posted 2003) [#9]
Over to you MattG !


Rob(Posted 2003) [#10]
The ones in code archives worked fine back when I was developing the max exporter.


Floyd(Posted 2003) [#11]
I hope we're all talking about the same code.

Here's a test of the EulerToQuat function. It has problems.

; Quat.bb : v1.0 : 15/11/02

; A tutorial on how to use this file is at http://www.dscho.co.uk/blitz/tutorials/quaternions.shtml

; Types
Type Rotation
	Field pitch#, yaw#, roll#
End Type

Type Quat
	Field w#, x#, y#, z#
End Type

; convert a Rotation to a Quat
Function EulerToQuat(out.Quat, src.Rotation)
	; NB roll is inverted due to change in handedness of coordinate systems
	Local cr# = Cos(-src\roll/2)
	Local cp# = Cos(src\pitch/2)
	Local cy# = Cos(src\yaw/2)

	Local sr# = Sin(-src\roll/2)
	Local sp# = Sin(src\pitch/2)
	Local sy# = Sin(src\yaw/2)

	; These variables are only here to cut down on the number of multiplications
	Local cpcy# = cp * cy
	Local spsy# = sp * sy
	Local spcy# = sp * cy
	Local cpsy# = cp * sy

	; Generate the output quat
	out\w = cr * cpcy + sr * spsy
	out\x = sr * cpcy - cr * spsy
	out\y = cr * spcy + sr * cpsy
	out\z = cr * cpsy - sr * spcy
End Function

; convenience function to fill in a rotation structure
Function FillRotation(r.Rotation, pitch#, yaw#, roll#)
	r\pitch = pitch
	r\yaw = yaw
	r\roll = roll
End Function


; **********************************************************************

; Test 90 degree rotation around X+ axis: pitch = 90, yaw = roll = 0.

; Resulting quaternion rotates 90 degrees around Y+ axis.


q.quat = New quat
r.rotation = New rotation

fillrotation r,  90, 0, 0

EulerToQuat q, r

Print " Axis:   " + q\x + ",   " + q\y + ",   " + q\z

Print "Angle:   " + ( 2 * ACos(q\w) )

WaitKey : End


It should produce a rotation around the X-axis, but actually produces rotation around Y-axis.


Wavey(Posted 2003) [#12]
Floyd: Quaternions are *not* the same as (angle, axis) format, and so shouldn't be interpreted that way. Have a look at http://www.gamasutra.com/features/19980703/quaternions_01.htm for some background info (it also briefly mentions the differences between the two representations).


Floyd(Posted 2003) [#13]
Quaternions are essentially the same as angle/axis, with some restrictions.

Quaternion (w,x,y,z) represents a rotation around an axis.

1. The axis points in the same direction as vector (x,y,z).
2. w is the cosine of half the angle of rotation.
3. The quaternion is scaled so it has length 1.

For example, consider a rotation of 120 degrees around the Y+ axis.
The angle is 120, so w is Cos(60).

(x,y,z) must point in the direction of (0,1,0).
This can be anything of the form (0,y,0), where y is a positive number.
But rule #3 says w*w + x*x + y*y + z*z = 1.0, so 0.25 + y*y = 1.0.
So y must be Sqr(0.75).

Thus the quaternion (w, x, y, z) is about ( 0.5, 0, 0.866, 0 ).

But if you try this with the test code EulerToQuat gives (x,y,z) = ( 0, 0, 0.866 ).

The coordinates x,y,z are mixed up. And a change in handedness can't explain this.
That would change the sign of something, interchanging positive and negative.


Wavey(Posted 2003) [#14]
Sorry, you're right. The functions were imported from a number of sources, so I don't know why it's behaving incorrectly. When I was testing them, I only used EulerToQuat then QuatToEuler, I don't think I paid much attention to what was actually in the Quat.

I don't currently have access to Blitz (or for the next few months), so if anyone would like to fix it and put it back in the code archives, they're more than welcome.


Ricky Smith(Posted 2003) [#15]
The function is ok as long as you do the following:

Reassign the resulting x,y and z components to :

z=x
x*-1=y
y*-1=z

the w component is ok.

Depending on which quat function you use this may alter slightly - I haven't found a quat function yet that does it right first time - they're ok when working with their own generated quats but using .b3d quaternion animation keys they screw up big time.