private void ConfigureAxes() { Vector3 yawAxis = Vector3.Cross(_pitchAxis, _rollAxis); _axes = new AirfoilAxis[3]; _axes[0] = new AirfoilAxis(_pitchAxis, _rollAxis); // Pitch _axes[1] = new AirfoilAxis(_rollAxis, yawAxis); // Yaw _axes[2] = new AirfoilAxis(yawAxis, _rollAxis); // Roll }
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; } } } }