Unity aircraft physics
Asked Answered
S

1

7

I want to make a simple aircraft controller, what looks like little realistic in unity. I watch some video from airplane physics. and make a simple script in unity, but if I start, my plane cant move or if I change drag to zero, it cant lift. I tried to use real data and get it from wiki(F22 Raptor). To my game object, I gave the rigidbody component mass = 19670 kg. Engine thrust = 2 * 116000.0f Newton.

    private void calculateEnginePower()
    {
        EnginePower = engineThrust * ThrottleInput;
    }

    private void calculateForces()
    {
        angleOfAttack = Vector3.Angle(Vector3.forward, rb.velocity);
        angleOfAttack = Mathf.Clamp(angleOfAttack, 0, 90);

        coefficient = Mathf.Pow(1225.04f * rb.velocity.magnitude, 2) - 1; //M^2-2 where: M is mach.         

        if (coefficient > 0.0f)
            coefficientLift = (4 * angleOfAttack) / Mathf.Sqrt(coefficient);
        lift = 1.2754f * 0.5f * Mathf.Pow(rb.velocity.magnitude, 2) * coefficientLift * 78.04f; // densy1.2754 kg/m3, speed m/s , (F22)Wing area: 840 ft² (78.04 m²)

        coefficientDrag = 0.021f;
        rb.drag = coefficientDrag * 0.5f * Mathf.Pow(rb.velocity.magnitude,2) * 1.2754f * 78.04f;

        rb.AddForce(transform.up * lift);
        rb.AddForce(transform.forward * EnginePower);
    }

used these formulas:

for Lift force: Lift formula for Lift coefficient: Cl formula for Drag: Drag formula and for Drag coefficient: I used data from wiki too (0.021f).

Schauer answered 8/4, 2018 at 10:39 Comment(4)
Have you tried debugging to see the values of lift and EnginePower? Where are you calling calculateForces?Alo
roll,pitch... inputs from keyboard and mouse, EnginePower is a simple property and i call the Move function in a controller inside void Update. public void Move(float roll, float pitch, float yaw, float throttle) { // transfer input parameters into properties.s RollInput = roll; PitchInput = pitch; YawInput = yaw; ThrottleInput = throttle; AirBrakes = false; calculateEnginePower(); calculateForces(); calculateRotation(); }Schauer
you can call it too in Move function for debugging. private void debugThings() { Debug.Log("Aoa: " + angleOfAttack); Debug.Log("cL: " + coefficientLift); Debug.Log("Lift: " + lift); Debug.Log("cD: " + coefficientDrag); Debug.Log("Drag: " + drag); Debug.Log("Mass: " + rb.mass); Debug.Log("Speed: " + rb.velocity.magnitude); Debug.DrawLine(rb.position, rb.velocity * 300, Color.red); }Schauer
What are typical values for lift at full thrust? How do they compare to the weight of the plane? (g might not be 9.81 in Unity units, but I'm unsure about that - best way is to find out with an experiment). According to this forum the drag property seems to have rather arbitrary units (and it is unclear what it exactly represents)Carner
G
23

So there are a number of issues with your code. I've outlined them below;

Calculate Forces


Issue: angleOfAttack = Vector3.Angle(Vector3.forward, rb.velocity);

  • Vector3.forward and rb.velocity are both in world-space. AoA is the angle between the local chord-line of your wing and the aircraft's velocity.
  • Vector3.Angle will return an unsigned angle. AoA must work in both positive and negative directions otherwise negative pitch and inverted flight would not be possible.

Solution: Move rb.velocity to local-space and solve for AoA with trigonometry.

// *flip sign(s) if necessary*
var localVelocity = transform.InverseTransformDirection(rb.velocity);
var angleOfAttack = Mathf.Atan2(-localVelocity.y, localVelocity.z);

Issue: coefficient = Mathf.Pow(1225.04f * rb.velocity.magnitude, 2) - 1;

  • 4α/sqrt(M^2−1) is a supersonic wave coefficient for M > 1. At zero velocity this equation will reduce to sqrt(-1) which is an imaginary number that will produce NaN. Mach is expressed as M=V/C where V=velocity and C=the speed of sound. Your 1225.04f constant must be C in units of km/h and not m/s as required. You're also multiplying and not dividing as given in the equation.

Solution: Simplify your equations with Lifting Line Theory.

var aspectRatio = (wingSpan * wingSpan) / wingArea; 
var inducedLift = angleOfAttack * (aspectRatio / (aspectRatio + 2f)) * 2f * Mathf.PI;
var inducedDrag = (inducedLift * inducedLift) / (aspectRatio * Mathf.PI);

Source: Aerospaceweb.org


Issue: rb.drag = coefficientDrag * 0.5f * Pow(rb.velocity.mag,2) * 1.2754f * 78.04f;

  • rb.drag is not required since we're calculating and applying drag manually.

Solution: Set the rb.drag property to the smallest possible value.

rb.drag = Mathf.Epsilon; // set in Awake

Issue: rb.AddForce(transform.up * lift);

  • transform.up is not correct for lift. Lift acts perpendicular to velocity while drag acts parallel.

Solution: Compute the lift direction by crossing the normalized velocity vector with the aircraft's lateral direction and apply drag opposite to velocity.

// *flip sign(s) if necessary*
var dragDirection = -rb.velocity.normalized;
var liftDirection = Vector3.Cross(dragDirection, transform.right);
rb.AddForce(liftDirection * lift + dragDirection * drag);

Your lift equation looks OK, so putting it all together would look something like this; (Untested)

public float wingSpan = 13.56f;
public float wingArea = 78.04f;

private float aspectRatio;

private void Awake ()
{
    rb.drag = Mathf.Epsilon;
    aspectRatio = (wingSpan * wingSpan) / wingArea;
}

private void calculateForces ()
{
    // *flip sign(s) if necessary*
    var localVelocity = transform.InverseTransformDirection(rb.velocity);
    var angleOfAttack = Mathf.Atan2(-localVelocity.y, localVelocity.z);

    // α * 2 * PI * (AR / AR + 2)
    var inducedLift = angleOfAttack * (aspectRatio / (aspectRatio + 2f)) * 2f * Mathf.PI;

    // CL ^ 2 / (AR * PI)
    var inducedDrag = (inducedLift * inducedLift) / (aspectRatio * Mathf.PI);

    // V ^ 2 * R * 0.5 * A
    var pressure = rb.velocity.sqrMagnitude * 1.2754f * 0.5f * wingArea;

    var lift = inducedLift * pressure;
    var drag = (0.021f + inducedDrag) * pressure;

    // *flip sign(s) if necessary*
    var dragDirection = rb.velocity.normalized;
    var liftDirection = Vector3.Cross(dragDirection, transform.right);

    // Lift + Drag = Total Force
    rb.AddForce(liftDirection * lift - dragDirection * drag);
    rb.AddForce(transform.forward * EnginePower);
}
Gradus answered 9/4, 2018 at 7:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.