I don't need to test my programs. I have an error-correcting modem.

Legacy:Quaternion Rotation

From Unreal Wiki, The Unreal Engine Documentation Site
Jump to: navigation, search

If you want to know what quaternions are and what they are good or, please read the appropriate page first.

This page will simply describe how to use a quaternion to calculate the player's rotation. This could be very useful for spaceships and to avoid gimbal lock.

Rotation Maths[edit]

First, a global quaternion var (quat) has to be declared for the player, let's call it "QuatRotation". This should be initialised to a straight rotation, I did it like this:

QuatRotation = QuatFromAxisAndAngle( Vect(1,0,0), 0.0 );

Note that because the angle is zero, the quaternion will be the same regardless of what vector we supply as the axis. For this reason, there is no point in setting the starting quat's axis to the vector rotation of the player.

In UpdateRotation(), the rotations about the different axis can be done like this:

// Roll
RotQuat = QuatFromAxisAndAngle( vect(1,0,0), DeltaTime * Amount );
QuatRotation = QuatProduct(QuatRotation, RotQuat);
 
// Yaw
RotQuat = QuatFromAxisAndAngle( vect(0,0,1), DeltaTime * Amount );
QuatRotation = QuatProduct(QuatRotation, RotQuat);
 
// Pitch
RotQuat = QuatFromAxisAndAngle( vect(0,1,0), DeltaTime * Amount );
QuatRotation = QuatProduct(QuatRotation, RotQuat);

Where Amount is the amount we want to turn among the certain axis. So we simply create a new rotation quaternion for each rotation and then apply this rotation to our rotation quaternion. I don't know if this is the best way to do it, but it works.

Converting the quaternion to a rotator[edit]

Finally we have to convert the quaternion to a rotator, so we can set the rotation with SetRotation(). This turned out to be more tricky than I hoped. However, this function that I found on the net for another language (unfortunately I can't remember where I found it) finally did the job:

function Rotator QuatToRotator(quat Q)
{
    local float sqx, sqy, sqz, sqw;
    local Rotator Rotator;
 
    sqx = Q.X*Q.X;
    sqy = Q.Y*Q.Y;
    sqz = Q.Z*Q.Z;
    sqw = Q.W*Q.W;
 
    Rotator.Yaw = atan(2.0 * (Q.X*Q.Y + Q.Z*Q.W), (sqx - sqy - sqz + sqw)) * 10430.3783505; 
    Rotator.Roll = atan(2.0 * (Q.Y*Q.Z + Q.X*Q.W),(-sqx - sqy + sqz + sqw)) * -10430.3783505;
    Rotator.Pitch = asin(-2.0 * (Q.X*Q.Z - Q.Y*Q.W)) * -10430.3783505;
 
    return Rotator;
}

"10430.3783505" is simply the value to convert the resulting radians to URot units. This function has one major flaw though. Whenever I look straight up or down, it "flickers". This doesn't happen often, but it can happen. So if everyone knows a better way, feel free to fix or replace the above code.

Matariel: in UT2004 QuatToRotator and back as well as QuatSlerp are handled natively so you wont have to worry about that. Ut2003 though, Im afraid no such luck :/