Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm attempting to use a basic physics system to create an arcade flight model. So far I have managed to get the aircraft moving forward, apply gravity, etc. However, after trying to implement torque I noticed some interesting behaviour in the flight model. When turning after a while the controls appear to reverse, sometimes, the controls for the different movements (pitch, roll, yaw) also seem to change. I was hoping that someone may be able to advise me as to what I should check next. I have included my source code in case anyone spots any glaring mistakes! I have listed some of the variables below to show their data types:

Quaternion rotation = Quaternion.Identity;
Quaternion newRotation = Quaternion.Identity;
Vector3 rotationChange = Vector3.Zero;
Vector3 rotVec = Vector3.Zero;

Below is the update logic for the rotational forces:

dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
if (dt > 1.0f / 60.0f)
{
    dt = 1.0f / 60.0f;
}

Vector3 newRotationChange = rotationChange + dt * angularAcceleration;
Vector3 newRotVec = rotVec + dt * newRotationChange;

rotationChange = newRotationChange;
rotVec = newRotVec;

Vector3 rotAxis = rotVec;
rotAxis.Normalize();

if (rotVec.Length() < 0.001f)
{
    rotVec = Vector3.Zero;
    newRotation = Quaternion.CreateFromAxisAngle(forwardVector, 0.0f);
}
else
{
    float angle = rotVec.Length();
    newRotation = Quaternion.CreateFromAxisAngle(rotAxis, angle);
}

if (rotationChange.Length() < 0.001f)
{
    rotationChange = Vector3.Zero;
}

rotation = newRotation;
angularAcceleration = Vector3.Zero;

My method for creating the torque:

/// <summary>
/// Creates a rotational force for an object
/// </summary>
/// <param name="pointOfAction">Point the force is being applied on the object
/// </param>
/// <param name="forceAmount">Magnitude of the force being applied</param>
/// <param name="forceDir">Direction of the force being applied</param>
public void CreateTorque(Vector3 pointOfAction, float forceAmount, Vector3
        forceDir)
{
    // Vector from position to pointOfAction
    Vector3 r = pointOfAction - position;

    // Create the force
    Vector3 force = forceDir * forceAmount;

    // Create the torque force
    torque = Vector3.Cross(r, force);

    angularAcceleration += torque;
}

Sorry for the massive code block and thanks in advance for any help you can give.

share|improve this question
    
When you apply a crossproduct you have to keep in mind that there are 2 vectors that are normal to the plane defined by the 2 vectors. Crossproduct will return one of them based on the angle between the two vectors. It is likely that it flips when it hits the point where the crossproduct returns the other normal. –  RobCurr Feb 27 '13 at 18:26
    
Hi @RobCurr thanks for your feedback. Could you suggest a method for counteracting this? Again, thanks for your response. –  Steve Locke Feb 27 '13 at 19:16
    
I managed it in my own project by checking the sign of the y component of the resulting normal vector but my case was different in that my game object was constrained in space which is not the case for yours. –  RobCurr Feb 27 '13 at 19:33
    
Thanks for your help @RobCurr this has at least given me a pointer as to where to look next! –  Steve Locke Feb 27 '13 at 21:02
    
@RobCurr The cross product will never 'randomly' start returning the other normal; while there are two normals to the plane, the cross-product is a well-defined function of the two vectors being crossed, and you can't expect arbitrarily flipping it to do the right thing. –  Steven Stadnicki Mar 30 '13 at 4:56

2 Answers 2

up vote 3 down vote accepted

Ok so I finally managed to work out what I was doing wrong. The issue was how I was applying the rotation vector to the quaternion. Basically rather than use Quaternion.CreateFromAxisAngle() I now create a rotation change Quaternion using my angular velocity as the X,Y,Z components and 0 for the scalar. So just for clarity here is my new update code for rotational physics. ( This replaces every line of code after calculating dt)

Vector3 newAngularVelocity = angularVelocity + dt * angularAcceleration;
Quaternion rotChange = 
    new Quaternion(angularVelocity.X, angularVelocity.Y, angularVelocity.z, 0);
rotChange = Quaternion.Multiply(rotChange, dampeningFactor) * rotation;
rotation += rotChange * dt;
rotation.Normalize();

angularVelocity = newAngularVelocity;
angularAcceleration = Vector3.Zero;

Hopefully this proves helpful to someone else!

share|improve this answer
    
it appears that what I was considering a 'dampening factor' actually requires a particular value. This needs to be 0.5 otherwise the code does not acheive the desired result. –  Steve Locke Sep 18 '13 at 10:13

Whenever you use .CreateFromAxisAngle() it is necessary to supply a unit length vector for the axis param. If you don't, it will over or under rotate the result since the axis magnitude is a factor in the rotation calculation.

Try normalizing it like this:

else
{
    float angle = rotVec.Length();
    rotVec /= angle;//this normalizes rotVec
    newRotation = Quaternion.CreateFromAxisAngle(rotVec, angle);// use 'rotVec' as the axis, not rotAxis
}
share|improve this answer
    
Hi @Steve H, I have tried the modifications you have suggested but it still produces the same behaviour. I was wondering whether or not the rotation quaternion could be looping? Thanks for your response. –  Steve Locke Feb 28 '13 at 12:51
    
I think the original code already did what you suggested. It does it using Vector3.Normalize(), rather than dividing the vector by its length. The library method probably prevents divide by zero errors, but yours will not. –  Seth Battin Mar 30 '13 at 5:50

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.