Exemple #1
0
    private void FixedUpdate()
    {
        if (_wind == null)
        {
            return;
        }

        if (OnPreFixedUpdate != null)
        {
            OnPreFixedUpdate(this);
        }

        Vector3 centerPosition = transform.position;

        Vector3 windVelocity = _wind.GetWindVelocity(centerPosition);
        float   airDensity   = _wind.GetAirDensity(centerPosition);

        RelativeVelocity = _body.velocity - windVelocity;
        AirSpeed         = RelativeVelocity.magnitude;

        Vector3 force = -RelativeVelocity.normalized * (0.5f * airDensity * _referenceArea * AirSpeed * AirSpeed * _cDrag); // Todo: optimize by not normalizing relative velocity

        _body.AddForceAtPosition(force, transform.position);

        if (OnPostFixedUpdate != null)
        {
            OnPostFixedUpdate(this);
        }
    }
    private void UpdateStatistics()
    {
        /* Note: Calculating position derivatives in Update caused framerate dependent effects to happen
         * (which is what caused the OrbitCamera to lag behind at low fps) */

        /* Update altitudes. */
        _altitudeSeaLevel = _body.transform.position.y;
        RaycastHit hit;

        if (Physics.Raycast(_body.transform.position, Vector3.down, out hit, Mathf.Infinity, _layerMask))
        {
            _altitudeGround = hit.distance;
            //Debug.Log("I hit this thang: " + hit.collider.name);
        }

        /* Find position derivatives. */
        Vector3 velocity    = _body.velocity;
        Vector3 oldVelocity = RigidbodyState.Lerp(_historyBuffer, Time.fixedTime - 0.25f).Velocity;

        _acceleration = (velocity - oldVelocity) / 0.25f;

        Vector3 localAngularVelocity = _body.transform.InverseTransformDirection(_body.angularVelocity);

        _localAngularAcceleration = localAngularVelocity - _localAngularVelocity;
        _localAngularVelocity     = localAngularVelocity;

        /* Determine relative wind vector. */
        Vector3 windVelocity = _wind.GetWindVelocity(_body.transform.position);

        _relativeVelocity = _body.velocity - windVelocity;
        _trueAirspeed     = _relativeVelocity.magnitude;

        /* Determine angle of attack. */
        Vector3 v1 = _body.transform.TransformDirection(_rollAxis);
        Vector3 v2 = _relativeVelocity.normalized;
        Vector3 n  = _body.transform.TransformDirection(_pitchAxis);

        _angleOfAttack = MathUtils.AngleAroundAxis(v1, v2, n);

        /* Determine glide ratio. */
        float horizontalDistance = Mathf.Sqrt(Mathf.Pow(_body.velocity.x, 2f) + Mathf.Pow(_body.velocity.z, 2f));
        float verticalDistance   = -_body.velocity.y;

        _glideRatio = horizontalDistance / verticalDistance;

        /* Determine Angle to ground for local axes. */
        Vector3 rollAxisCenter = _body.transform.forward;

        _angleToGroundRoll = MathUtils.AngleAroundAxis(Vector3.down, rollAxisCenter,
                                                       _body.transform.TransformDirection(_rollAxis));
        Vector3 forward          = _body.transform.TransformDirection(_rollAxis);
        Vector3 projectedForward = new Vector3(forward.x, 0f, forward.z);

        _angleToGroundPitch = MathUtils.AngleAroundAxis(projectedForward, forward,
                                                        _body.transform.TransformDirection(_pitchAxis));

        _historyBuffer.Enqueue(RigidbodyState.ToImmutable(_body, Time.fixedTime));
    }
    void Update()
    {
        Vector3 windVelocity = _wind.GetWindVelocity(_transform.position);
        Vector3 velocity     = (_transform.position - _lastPosition) / _gameClock.DeltaTime;

        _lastPosition = _transform.position;
        Vector3 relativeVelocity = velocity - windVelocity;

        relativeVelocity.Normalize();

        _airspeed      = Mathf.Lerp(_airspeed, _statistics.TrueAirspeed, 20f * _gameClock.DeltaTime);
        _angleOfAttack = Mathf.Lerp(_angleOfAttack, _statistics.AngleOfAttack, 20f * _gameClock.DeltaTime);

        _airspeedParam.setValue(_airspeed);
        _angleOfAttackParam.setValue(_angleOfAttack);
        _groundProximityParam.setValue(_statistics.AltitudeGround);
    }
    private void FixedUpdate()
    {
        if (_body == null || _wind == null)
        {
            return;
        }

        if (OnPreFixedUpdate != null)
        {
            OnPreFixedUpdate(this);
        }

        Vector3 centerPosition = transform.position;

        Vector3 windVelocity = _wind.GetWindVelocity(centerPosition);
        float   airDensity   = _wind.GetAirDensity(centerPosition);

        RelativeVelocity = _body.velocity - windVelocity;
        AirSpeed         = RelativeVelocity.magnitude;

        Vector3 worldLongitudinalAxis = transform.TransformDirection(_longitudinalAxis);
        Vector3 axis = Vector3.Cross(worldLongitudinalAxis, RelativeVelocity).normalized;

        AngleOfAttack = MathUtils.AngleAroundAxis(worldLongitudinalAxis, RelativeVelocity, axis);

        float liftCoefficient = _liftCoeffients.Evaluate(AngleOfAttack) * _liftCoefficientMultiplier;
        float dragCoefficient = _dragCoeffients.Evaluate(AngleOfAttack) * _dragCoefficientMultiplier;

        float dynamicSurfacePressure = 0.5f * airDensity * _referenceArea * AirSpeed * AirSpeed;

        // Todo: can optimize by not normalizing relative velocity
        LiftForce = Vector3.Cross(RelativeVelocity, axis).normalized *(dynamicSurfacePressure * liftCoefficient);
        DragForce = -RelativeVelocity.normalized * (dynamicSurfacePressure * dragCoefficient);

        _body.AddForceAtPosition(LiftForce + DragForce, transform.position);

        if (OnPostFixedUpdate != null)
        {
            OnPostFixedUpdate(this);
        }
    }
Exemple #5
0
    void OnDrawGizmos()
    {
        if (!Application.isPlaying)
        {
            return;
        }

        float horizontalStepsize = _horizontalSize / _horizontalSteps;
        float verticalStepsize   = _verticalSize / _verticalSteps;
        float horizontalHalfSize = _horizontalSize * 0.5f;
        float verticalHalfSize   = _verticalSize * 0.5f;

        Vector3 bottomLeft = transform.position - new Vector3(horizontalHalfSize, verticalHalfSize, horizontalHalfSize);

        for (int x = 0; x < _horizontalSteps; x++)
        {
            float xPos = x * horizontalStepsize;

            for (int y = 0; y < _verticalSteps; y++)
            {
                float yPos = y * verticalStepsize;

                for (int z = 0; z < _horizontalSteps; z++)
                {
                    float zPos = z * horizontalStepsize;

                    Vector3 position   = bottomLeft + new Vector3(xPos, yPos, zPos);
                    Vector3 windVector = _wind.GetWindVelocity(position) * _drawScale;

                    Gizmos.color = Color.green;
                    Gizmos.DrawRay(position, windVector);
                    Gizmos.color = Color.red;
                    Gizmos.DrawSphere(position, 0.25f);
                }
            }
        }
    }
Exemple #6
0
    private void EvaluateForces()
    {
        Vector3 position = _transform.position;

        Vector3 windVelocity = _wind.GetWindVelocity(position);
        float   airDensity   = _wind.GetAirDensity(position);

        Vector3 velocity = (position - _lastPosition) / Time.deltaTime;

        _lastPosition    = position;
        RelativeVelocity = velocity - windVelocity;
        AirSpeed         = RelativeVelocity.magnitude;

        Vector3 relativeDirection = RelativeVelocity.normalized;

        float dynamicSurfacePressure = 0.5f * airDensity * _surfaceArea * AirSpeed * AirSpeed;

        // Bug: This method of determining angle of attack only works for the default axis configuration!!
        // Bug: if lift coeff goes negative, we get NaNs really quickly!

        Vector3 localRelativeVelocity = _transform.InverseTransformDirection(RelativeVelocity);
        Vector2 pitchPlaneVelocity    = new Vector2(localRelativeVelocity.z, localRelativeVelocity.y);

        AngleOfAttack = AngleSigned(Vector2.right, pitchPlaneVelocity);

        if (float.IsNaN(AngleOfAttack))
        {
            Debug.LogError("Angle of Attack is NaN " + RelativeVelocity);
#if UNITY_EDITOR
            EditorApplication.isPlaying = false;
#endif
            return;
        }

        Vector3 worldAxis = _transform.TransformDirection(_pitchAxis);

        Vector3 linearForce = Vector3.zero;

        if (_liftResponse.Enabled)
        {
            float   liftCoefficient = _liftResponse.Coefficients.Evaluate(AngleOfAttack) * _liftResponse.Multiplier;
            float   liftMagnitude   = dynamicSurfacePressure * liftCoefficient * Efficiency;
            Vector3 liftDirection   = Vector3.Cross(relativeDirection, worldAxis);
            LiftForce    = liftDirection * liftMagnitude;
            linearForce += LiftForce;
        }

        if (_dragResponse.Enabled)
        {
            float dragCoefficient = _dragResponse.Coefficients.Evaluate(AngleOfAttack) * _dragResponse.Multiplier;
            float dragMagnitude   = dynamicSurfacePressure * dragCoefficient * Efficiency;
            DragForce    = relativeDirection * -dragMagnitude;
            linearForce += DragForce;
        }

        if (_momentResponse.Enabled)
        {
            float momentCoefficient = _momentResponse.Coefficients.Evaluate(AngleOfAttack) * _momentResponse.Multiplier;
            float momentMagnitude   = dynamicSurfacePressure * momentCoefficient;
            MomentForce = worldAxis * momentMagnitude;
        }

        Vector3 pressurePoint = _transform.TransformPoint(_chordPressurePoint); // Todo: only needed if applying force from within this script

        if (_body)
        {
            _body.AddForceAtPosition(linearForce, pressurePoint);
            _body.AddTorqueAtPosition(MomentForce, _rollAxis, pressurePoint, ForceMode.Force);
        }
    }
Exemple #7
0
    private void EvaluateForces()
    {
        Transform wingTransform = transform;
        Vector3   wingPosition  = wingTransform.position;

        Vector3 windVelocity = _wind.GetWindVelocity(wingPosition);
        float   airDensity   = _wind.GetAirDensity(wingPosition);

        Vector3 velocity = (wingPosition - _lastPosition) / Time.deltaTime;

        _lastPosition    = wingPosition;
        RelativeVelocity = velocity - windVelocity;
        AirSpeed         = RelativeVelocity.magnitude;

        const float groundEffectHeight     = 32f;
        const float groundEffectPow        = 2f;
        float       groundEffectMultiplier = 1f;
        RaycastHit  hit;

        if (Physics.Raycast(_body.transform.position, Vector3.down, out hit, groundEffectHeight, _layerMask))
        {
            groundEffectMultiplier += Mathf.Pow(Mathf.InverseLerp(groundEffectHeight, 0f, hit.distance), groundEffectPow);
        }

        UpdateStats(wingTransform);

        // Calculate forces per section of the wing
        for (int i = 0; i < _numSections; i++)
        {
            var section = _sectionStates[i];

            Vector3 sectionWorldPosition = wingTransform.TransformPoint(section.LocalPosition);
            Vector3 sectionWorldVelocity = (sectionWorldPosition - section.LastSectionWorldPosition) / Time.fixedDeltaTime;
            section.LastSectionWorldPosition = sectionWorldPosition;
            section.RelativeVelocity         = sectionWorldVelocity - windVelocity;

            section.AirSpeed = section.RelativeVelocity.magnitude;

            float dynamicPressure = 0.5f * airDensity * section.AirSpeed * section.AirSpeed * groundEffectMultiplier;

            section.Lift   = Vector3.zero;
            section.Drag   = Vector3.zero;
            section.Moment = Vector3.zero;

            //Vector3 localRelativeVelocity = wingTransform.InverseTransformDirection(section.RelativeVelocity);

            // Calculate the effects around each axis
            for (int j = 0; j < _components.Length; j++)
            {
                AirfoilAxisResponse coefficient = _components[j];
                AirfoilAxis         airfoilAxis = _axes[(int)coefficient.AxisType];

                Vector3 worldAxis     = wingTransform.TransformDirection(airfoilAxis.Axis);
                Vector3 worldAxisBase = wingTransform.TransformDirection(airfoilAxis.AxisZero);

                // Todo: Collapse this all into 2D calculations around the coefficient axis

                Vector3 projectedVelocity = section.RelativeVelocity - Vector3.Project(section.RelativeVelocity, worldAxis);
                section.AngleOfAttack = MathUtils.AngleAroundAxis(worldAxisBase, projectedVelocity, worldAxis);
                Vector3 sectionRelativeDirection = projectedVelocity.normalized;

                float forceCoefficient = coefficient.Coefficients.Evaluate(section.AngleOfAttack + section.Offset) * coefficient.Multiplier;
                float forceMagnitude   = dynamicPressure * section.SurfaceArea * forceCoefficient;

                var input = new SectionForceInput()
                {
                    body                     = _body,
                    force                    = forceMagnitude,
                    efficiency               = _efficiency,
                    section                  = section,
                    sectionWorldPosition     = sectionWorldPosition,
                    sectionRelativeDirection = sectionRelativeDirection,
                    worldAxis                = worldAxis,
                    worldAxisZero            = worldAxisBase
                };

                //ForceApplicators[(int) coefficient.Type](input);
                switch (coefficient.Type)
                {
                case ForceType.Lift:
                    ApplyLift(input);
                    break;

                case ForceType.Drag:
                    ApplyDrag(input);
                    break;

                case ForceType.Moment:
                    ApplyMoment(input);
                    break;
                }
            }
        }
    }
        private void EvaluateForces()
        {
            UpdateBodyMatrix();

            var liftPressurePoint = _bodyMatrix.MultiplyPoint(_chordPressurePoint);
            var dragPressurePoint = _bodyMatrix.MultiplyPoint(_chordPressurePoint);
            var windVelocity      = _wind.GetWindVelocity(liftPressurePoint);
            var airDensity        = _wind.GetAirDensity(liftPressurePoint);

            var velocity = (liftPressurePoint - _lastPosition) / _fixedClock.DeltaTime;

            _lastPosition    = liftPressurePoint;
            RelativeVelocity = velocity - windVelocity;
            var relativeDirection = RelativeVelocity.normalized;

            var localRelativeVelocity = _bodyMatrix.inverse.MultiplyVector(RelativeVelocity);
            var pitchPlaneVelocity    = new Vector2(localRelativeVelocity.z, localRelativeVelocity.y);

            AngleOfAttack = AngleSigned(Vector2.right, pitchPlaneVelocity.normalized);

            AirSpeed = pitchPlaneVelocity.magnitude;
            var dynamicSurfacePressure = 0.5f * airDensity * _surfaceArea * AirSpeed * AirSpeed;

            var worldAxis   = _bodyMatrix.MultiplyVector(Vector3.right);
            var linearForce = Vector3.zero;

            DeflectionInputs[0] = 1f - Mathf.Min(1f, DeflectionInputs[1] + DeflectionInputs[2] + DeflectionInputs[3]);

            var c = _definition.GetInterpolated(AngleOfAttack, DeflectionInputs);

            var   liftMagnitude = dynamicSurfacePressure * c.Lift * Mathf.Pow(_sliderFactor, 3f) * _optimalPressureFactor * _optimalPressureFactor;
            float aspectFactor  = 1f - 1f / Mathf.Pow(_totalAspectRatio, 0.5f); // Todo: Stupid simple way to make aspect ratio matter, improve

            liftMagnitude *= aspectFactor;

            var liftDirection = Vector3.Cross(relativeDirection, worldAxis);

            LiftForce    = liftDirection * liftMagnitude;
            linearForce += LiftForce;

            var dragMagnitude = dynamicSurfacePressure * c.Drag * SliderFactor * _optimalPressureFactor;

            DragForce    = relativeDirection * -dragMagnitude;
            linearForce += DragForce;

            var momentMagnitude = dynamicSurfacePressure * c.Moment;

            MomentForce = worldAxis * momentMagnitude;

            if (float.IsNaN(linearForce.magnitude) || float.IsNaN(linearForce.magnitude))
            {
                Debug.LogError("Airfoil Force is NaN " + RelativeVelocity + ", forcing quit...");
    #if UNITY_EDITOR
                EditorApplication.isPlaying = false;
    #else
                Application.Quit();
    #endif
                return;
            }

            if (_body)
            {
                _body.AddForceAtPosition(linearForce, liftPressurePoint);
                _body.AddTorqueAtPosition(MomentForce, dragPressurePoint, ForceMode.Force);
            }
        }