统一飞机物理
Unity aircraft physics
我想做一个简单的飞行器控制器,在unity中看起来有点逼真。我看了一些飞机物理学的视频。并统一制作一个简单的脚本,但如果我开始,我的飞机就不能移动,或者如果我将阻力改为零,它就不能升起。我尝试使用真实数据并从 wiki(F22 Raptor)获取它。对于我的游戏对象,我给刚体组件质量 = 19670 千克。
发动机推力 = 2 * 116000.0f 牛顿。
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);
}
使用了这些公式:
升力:
Lift formula
对于升力系数:
Cl formula
对于拖动:
Drag formula
以及风阻系数:我也使用了来自 wiki 的数据 (0.021f)。
所以您的代码存在很多问题。我在下面概述了它们;
计算力
Issue: angleOfAttack = Vector3.Angle(Vector3.forward, rb.velocity);
Vector3.forward
和rb.velocity
都在world-space中。 AoA
是机翼 local chord-line 与飞机 velocity
之间的角度。
Vector3.Angle
将 return 一个 无符号 角。 AoA
必须在 positive 和 negative 两个方向上工作,否则将无法实现负俯仰和倒飞。
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)
是M > 1的超声波系数。在零速度下,该方程将简化为 sqrt(-1)
,这是一个虚数,将产生 NaN
。 Mach 表示为 M=V/C
其中 V=velocity
和 C=the speed of sound
。您的 1225.04f
常量必须以 km/h 为单位 C
,而不是按要求 m/s。你也在乘法而不是除法,如等式中给出的那样。
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);
来源: Aerospaceweb.org
Issue:
rb.drag = coefficientDrag * 0.5f * Pow(rb.velocity.mag,2) * 1.2754f * 78.04f;
rb.drag
不是必需的,因为我们正在手动计算和应用阻力。
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
不适合 lift
。升降机 垂直 至 velocity
而 drag
与 平行 .
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);
你的升力方程看起来不错,所以把它们放在一起看起来像这样; (未测试)
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);
}
我想做一个简单的飞行器控制器,在unity中看起来有点逼真。我看了一些飞机物理学的视频。并统一制作一个简单的脚本,但如果我开始,我的飞机就不能移动,或者如果我将阻力改为零,它就不能升起。我尝试使用真实数据并从 wiki(F22 Raptor)获取它。对于我的游戏对象,我给刚体组件质量 = 19670 千克。 发动机推力 = 2 * 116000.0f 牛顿。
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);
}
使用了这些公式:
升力: Lift formula 对于升力系数: Cl formula 对于拖动: Drag formula 以及风阻系数:我也使用了来自 wiki 的数据 (0.021f)。
所以您的代码存在很多问题。我在下面概述了它们;
计算力
Issue:
angleOfAttack = Vector3.Angle(Vector3.forward, rb.velocity);
Vector3.forward
和rb.velocity
都在world-space中。AoA
是机翼 local chord-line 与飞机velocity
之间的角度。Vector3.Angle
将 return 一个 无符号 角。AoA
必须在 positive 和 negative 两个方向上工作,否则将无法实现负俯仰和倒飞。
Solution: Move
rb.velocity
to local-space and solve forAoA
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)
是M > 1的超声波系数。在零速度下,该方程将简化为sqrt(-1)
,这是一个虚数,将产生NaN
。 Mach 表示为M=V/C
其中V=velocity
和C=the speed of sound
。您的1225.04f
常量必须以 km/h 为单位C
,而不是按要求 m/s。你也在乘法而不是除法,如等式中给出的那样。
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);
来源: Aerospaceweb.org
Issue:
rb.drag = coefficientDrag * 0.5f * Pow(rb.velocity.mag,2) * 1.2754f * 78.04f;
rb.drag
不是必需的,因为我们正在手动计算和应用阻力。
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
不适合lift
。升降机 垂直 至velocity
而drag
与 平行 .
Solution: Compute the
lift
direction by crossing the normalizedvelocity
vector with the aircraft's lateral direction and applydrag
opposite tovelocity
.
// *flip sign(s) if necessary*
var dragDirection = -rb.velocity.normalized;
var liftDirection = Vector3.Cross(dragDirection, transform.right);
rb.AddForce(liftDirection * lift + dragDirection * drag);
你的升力方程看起来不错,所以把它们放在一起看起来像这样; (未测试)
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);
}