Below is some code that will allow you to use Quaternions in Unreal Tournament. These are taken from a brushbuilder made by Tarquin. All credit for the code goes to him. Other implementations have also been made to allow the use of Quaternions, but they should all be functionally similar. This quaternion definition has a minor bug which occurs when a full 180° rotation is applied, however, so be forewarned.
Contents
Quaternion definition
struct Quat { var() float W,X,Y,Z; };
Vector expression
// Sets the components of a vector. Vect cannot be used as it will not accept an expression. function vector eVect( float x , float y , float z ) { // for some reason vect() wont work when setting an array element local vector v ; v.x = x ; v.y = y ; v.z = z ; return v ; }
Converting Axial Rotation to a Quaternion
// Takes a vector representing an axis and an angle in radians. // Returns the quaternion representing a rotation of Theta about the axis. function quat RotationToQuat( vector Axis , float Theta ) { // Theta must be given in radians // Axis need not be normalised local quat Q ; local float L ; Axis = Normal( Axis ); Q.W = cos( Theta / 2 ) ; Q.X = Axis.X * sin( Theta / 2 ) ; Q.Y = Axis.Y * sin( Theta / 2 ) ; Q.Z = Axis.Z * sin( Theta / 2 ) ; // NORMALISE L = Sqrt( Q.W**2 + Q.X ** 2 + Q.Y ** 2 + Q.Z**2 ) ; Q.W /= L ; Q.X /= L ; Q.Y /= L ; Q.Z /= L ; return Q ; }
Daid303: Is this the same as the new "QuatFromAxisAndAngle" function?
Tarquin: in theory, yes, but there may be differences in which way the angle and axis are used.
Daid303: Ah, ok, thx :) It worked fine. I'm using some of this stuff in a C program i'm working on. Still looking for a way to do Vector(Quat) as you can do Vector(Rotator), but without doing this: Vector(Rotator(Quat))...
FrozenCow: Uhm... "a minor bug which occurs when a full 180° rotation is applied" Is there a way to fix this?
Tarquin: almost certainly. but it might involve your brain leaking out of your ears! thinking in 4 dimensions is hard. :(
Multipliplication in quaternions
Overloads the * operator to multiply quaternions.
final operator(16) quat * ( quat Q1 , quat Q2 ) { local vector V1 , V2 , Vp ; local quat Qp ; V1 = eVect( Q1.X , Q1.Y , Q1.Z ) ; V2 = eVect( Q2.X , Q2.Y , Q2.Z ) ; Qp.W = Q1.W * Q2.W - ( V1 dot V2 ) ; Vp = ( Q1.W * V2 ) + ( Q2.W * V1 ) - ( V1 cross V2 ) ; Qp.X = Vp.X ; Qp.Y = Vp.Y ; Qp.Z = Vp.Z ; return Qp ; }
Converting Quaternions to a Transformation Matrix
function matrix3x3 QuatToMatrix ( quat Q ) { local matrix3x3 M ; local float w,x,y,z ; w = Q.W ; x = Q.X ; y = Q.Y ; z = Q.Z ; M.a11 = 1 - ( 2 * y** 2 ) - ( 2 * z** 2 ) ; M.a12 = 2*x*y - 2*z*w ; M.a13 = 2*x*z + 2*y*w ; M.a21 = 2*x*y + 2*z*w ; M.a22 = 1 - 2*x**2 -2*z**2 ; M.a23 = 2*y*z - 2*x*w ; M.a31 = 2*x*z - 2*y*w ; M.a32 = 2*y*z + 2*x*w ; M.a33 = 1 - 2*x**2 - 2*y**2 ; /* 1 - 2Y - 2Z 2XY - 2ZW 2XZ + 2YW 2XY + 2ZW 1 - 2X - 2Z 2YZ - 2XW 2XZ - 2YW 2YZ + 2XW 1 - 2X - 2Y */ return M ; }
Matrix Functions
Functions to define a matrix and multiply a matrix and a vector, ie. apply the transformation the matrix represents to the vector.
function Matrix3x3 defMatrix9f( float a11,float a12,float a13, float a21,float a22,float a23,float a31,float a32,float a33 ) { local Matrix3x3 theMatrix ; theMatrix.a11 = a11 ; theMatrix.a12 = a12 ; theMatrix.a13 = a13 ; theMatrix.a21 = a21 ; theMatrix.a22 = a22 ; theMatrix.a23 = a23 ; theMatrix.a31 = a31 ; theMatrix.a32 = a32 ; theMatrix.a33 = a33 ; return theMatrix ; } static final operator(16) vector * ( Matrix3x3 M , vector v ) { local vector Mv , R1 , R2 , R3 ; R1.x = M.a11 ; R1.y = M.a12 ; R1.z = M.a13 ; R2.x = M.a21 ; R2.y = M.a22 ; R2.z = M.a23 ; R3.x = M.a31 ; R3.y = M.a32 ; R3.z = M.a33 ; Mv.x = R1 dot v ; Mv.y = R2 dot v ; Mv.z = R3 dot v ; return Mv ; }
Daid303: Ok, kept me busy for a good 2 days, but I think i've got it. A bit. The * operator of the matrix and the vector is wrong I think. (I can't find any info about it anywhere on the net) but here is what I found out:
R1 seems to point in the direction what Vect(1,0,0) would have after rotating. M * Vect(1,0,0) should return that, but it doesn't. I think it should be along the lines of:
static final operator(16) vector * ( Matrix3x3 M , vector v ) { local vector Mv , R1 , R2 , R3 ; R1.x = M.a11 ; R1.y = M.a12 ; R1.z = M.a13 ; R2.x = M.a21 ; R2.y = M.a22 ; R2.z = M.a23 ; R3.x = M.a31 ; R3.y = M.a32 ; R3.z = M.a33 ; Mv = R1 * V.X + R2 * V.Y + R3 * V.Z; return Mv ; }
But i'm not sure...