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);
}
lift
andEnginePower
? Where are you callingcalculateForces
? – Alolift
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 thedrag
property seems to have rather arbitrary units (and it is unclear what it exactly represents) – Carner