Unity飞行物理学

7

我想制作一个简单的飞行控制器,让它在unity中看起来更加真实。我看了一些与飞机物理相关的视频,并且在unity中编写了一个简单的脚本,但是当我启动时,我的飞机无法移动,如果我将阻力设置为零,则无法升空。我尝试使用真实数据,并从wiki(F22猛禽)获取数据。对于我的游戏对象,我给予了刚体组件质量=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力公式: Lift formula Lift系数公式: Cl formula 阻力公式: Drag formula 阻力系数公式:我也使用了维基百科上的数据(0.021f)。


1
你尝试过调试来查看 liftEnginePower 的值吗?你在哪里调用 calculateForces 函数? - Ian H.
滚动,俯仰...从键盘和鼠标输入,EnginePower是一个简单的属性,我在控制器中调用Move函数,在void Update内部。 public void Move(float roll, float pitch, float yaw, float throttle) { // 将输入参数转换为属性 RollInput = roll; PitchInput = pitch; YawInput = yaw; ThrottleInput = throttle; AirBrakes = false;计算引擎功率(); 计算力量(); 计算旋转();} - Boyesz
你可以在Move函数中调用它进行调试。私有的void debugThings() { Debug.Log("迎角: " + angleOfAttack); Debug.Log("升力系数: " + coefficientLift); Debug.Log("升力: " + lift); Debug.Log("阻力系数: " + coefficientDrag); Debug.Log("阻力: " + drag); Debug.Log("质量: " + rb.mass); Debug.Log("速度: " + rb.velocity.magnitude);Debug.DrawLine(rb.position, rb.velocity * 300, Color.red);} - Boyesz
在全推力下,“升力”(lift)的典型值是多少?它们与飞机重量相比如何?(在Unity单位中,“g”可能不是9.81,但我不确定-最好的方法是通过实验找出)。根据这个论坛,drag属性似乎具有相当任意的单位(而且不清楚它到底代表什么)。 - meowgoesthedog
1个回答

22

你的代码存在一些问题,我在下面列出了它们:

计算力


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

  • Vector3.forwardrb.velocity都是在世界空间中的。角度AoA是机翼局部弦线与飞行器速度之间的夹角。
  • Vector3.Angle将返回一个无符号角度。必须使AoA方向上工作,否则就不能实现负俯仰和倒置飞行。

解决方案: rb.velocity移动到局部空间,并使用三角函数求解AoA

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

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

  • M > 1时,4α/sqrt(M^2−1)是一个超音速波系数。在速度为零时,此方程将简化为sqrt(-1),它是一个虚数,将导致产生NaN。马赫数表示为M=V/C,其中V=速度C=声速。您的常量1225.04f必须是以千米/小时为单位的C,而不是所需的m/s。您还在乘法而不是给出的除法。

解决方案: 使用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


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

  • rb.drag不是必要的,因为我们正在手动计算和应用阻力。

解决方案:rb.drag属性设置为最小可能值。

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

问题: rb.AddForce(transform.up * lift);

  • transform.up不适用于lift。由于lift垂直于velocity,而drag平行于velocity

解决方案: 通过将规范化的velocity向量与飞机的横向方向相叉乘来计算lift方向,并在相反方向应用drag以对抗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);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接