Skip to content

Commit

Permalink
Added GenericWing (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
loco-choco committed Nov 8, 2022
1 parent 8fb167c commit 3199492
Show file tree
Hide file tree
Showing 5 changed files with 273 additions and 10 deletions.
263 changes: 263 additions & 0 deletions CustomShipLib/Modules/Aerodynamics/GenericWing.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
//MIT License
//Copyright(c) 2020 Ivan Pensionerov

//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:

//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.

//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.

using System;
using UnityEngine;

namespace SlateShipyard.Modules.Aerodynamics
{
//https://www.youtube.com/watch?v=p3jDJ9FtTyM&t=225s
//And https://ieeexplore.ieee.org/document/7152411
//And https://github.com/gasgiant/Aircraft-Physics/blob/master/Assets/Aircraft%20Physics/Core/Scripts/AeroSurface.cs

public class GenericWing : MonoBehaviour
{
public float SkinFriction;
public float WingArea;
public float AspectRatio;
public float LiftSlope;
public float ZeroLiftAngle;
public float StallAngleHigh;
public float StallAngleLow;

private float FlapAngle;
public float AirfoilChord;
public float AirfoilSpan;

public float FlapFraction;

private OWRigidbody Body;

public FluidDetector FluidDetector;

public void Awake()
{
FluidDetector = GetComponent<FluidDetector>();
}
public void Start()
{
Body = transform.GetAttachedOWRigidbody();
}

public void FixedUpdate()
{
Vector3 relativePos = transform.position - Body.transform.position;

CalculateForces(FluidDetector.GetRelativeFluidVelocity(), FluidDetector.GetFluidDensity(), relativePos, out var liftForce, out Vector3 torqueForce);

Body.AddForce(liftForce);
Body.AddTorque(torqueForce);
}

public void SetFlapAngle(float angle)
{
FlapAngle = Mathf.Clamp(angle, -Mathf.Deg2Rad * 50, Mathf.Deg2Rad * 50);
}

public void CalculateForces(Vector3 worldAirVelocity, float airDensity, Vector3 relativePosition, out Vector3 liftForce, out Vector3 torqueForce)
{
// Accounting for aspect ratio effect on lift coefficient.
float correctedLiftSlope = LiftSlope * AspectRatio /
(AspectRatio + 2 * (AspectRatio + 4) / (AspectRatio + 2));

// Calculating flap deflection influence on zero lift angle of attack
// and angles at which stall happens.
float theta = Mathf.Acos(2 * FlapFraction - 1);
float flapEffectivness = 1 - (theta - Mathf.Sin(theta)) / Mathf.PI;
float deltaLift = correctedLiftSlope * flapEffectivness * FlapEffectivnessCorrection(FlapAngle) * FlapAngle;

float zeroLiftAoaBase = ZeroLiftAngle * Mathf.Deg2Rad;
float zeroLiftAoA = zeroLiftAoaBase - deltaLift / correctedLiftSlope;

float stallAngleHighBase = StallAngleHigh * Mathf.Deg2Rad;
float stallAngleLowBase = StallAngleLow * Mathf.Deg2Rad;

float clMaxHigh = correctedLiftSlope * (stallAngleHighBase - zeroLiftAoaBase) + deltaLift * LiftCoefficientMaxFraction(FlapFraction);
float clMaxLow = correctedLiftSlope * (stallAngleLowBase - zeroLiftAoaBase) + deltaLift * LiftCoefficientMaxFraction(FlapFraction);

float stallAngleHigh = zeroLiftAoA + clMaxHigh / correctedLiftSlope;
float stallAngleLow = zeroLiftAoA + clMaxLow / correctedLiftSlope;

// Calculating air velocity relative to the surface's coordinate system.
// Z component of the velocity is discarded.
Vector3 airVelocity = transform.InverseTransformDirection(worldAirVelocity);
airVelocity = new Vector3(0f, airVelocity.y, airVelocity.z);

Vector3 dragDirection = transform.TransformDirection(airVelocity.normalized);
Vector3 liftDirection = Vector3.Cross(dragDirection, transform.right);

float area = AirfoilChord * AirfoilSpan;
float dynamicPressure = 0.5f * airDensity * airVelocity.sqrMagnitude;
float angleOfAttack = Mathf.Atan2(airVelocity.y, -airVelocity.z);

Vector3 aerodynamicCoefficients = CalculateCoefficients(angleOfAttack,
correctedLiftSlope,
zeroLiftAoA,
stallAngleHigh,
stallAngleLow);

Vector3 lift = liftDirection * aerodynamicCoefficients.x * dynamicPressure * area;
Vector3 drag = dragDirection * aerodynamicCoefficients.y * dynamicPressure * area;
Vector3 torque = -transform.right * aerodynamicCoefficients.z * dynamicPressure * area * AirfoilChord;


liftForce = lift + drag;
torqueForce = Vector3.Cross(relativePosition, liftForce);
torqueForce += torque;
}


private Vector3 CalculateCoefficients(float angleOfAttack,
float correctedLiftSlope,
float zeroLiftAoA,
float stallAngleHigh,
float stallAngleLow)
{
Vector3 aerodynamicCoefficients;

// Low angles of attack mode and stall mode curves are stitched together by a line segment.
float paddingAngleHigh = Mathf.Deg2Rad * Mathf.Lerp(15, 5, (Mathf.Rad2Deg * FlapAngle + 50) / 100);
float paddingAngleLow = Mathf.Deg2Rad * Mathf.Lerp(15, 5, (-Mathf.Rad2Deg * FlapAngle + 50) / 100);
float paddedStallAngleHigh = stallAngleHigh + paddingAngleHigh;
float paddedStallAngleLow = stallAngleLow - paddingAngleLow;

if (angleOfAttack < stallAngleHigh && angleOfAttack > stallAngleLow)
{
// Low angle of attack mode.
aerodynamicCoefficients = CalculateCoefficientsAtLowAoA(angleOfAttack, correctedLiftSlope, zeroLiftAoA);
}
else
{
if (angleOfAttack > paddedStallAngleHigh || angleOfAttack < paddedStallAngleLow)
{
// Stall mode.
aerodynamicCoefficients = CalculateCoefficientsAtStall(
angleOfAttack, correctedLiftSlope, zeroLiftAoA, stallAngleHigh, stallAngleLow);
}
else
{
// Linear stitching in-between stall and low angles of attack modes.
Vector3 aerodynamicCoefficientsLow;
Vector3 aerodynamicCoefficientsStall;
float lerpParam;

if (angleOfAttack > stallAngleHigh)
{
aerodynamicCoefficientsLow = CalculateCoefficientsAtLowAoA(stallAngleHigh, correctedLiftSlope, zeroLiftAoA);
aerodynamicCoefficientsStall = CalculateCoefficientsAtStall(
paddedStallAngleHigh, correctedLiftSlope, zeroLiftAoA, stallAngleHigh, stallAngleLow);
lerpParam = (angleOfAttack - stallAngleHigh) / (paddedStallAngleHigh - stallAngleHigh);
}
else
{
aerodynamicCoefficientsLow = CalculateCoefficientsAtLowAoA(stallAngleLow, correctedLiftSlope, zeroLiftAoA);
aerodynamicCoefficientsStall = CalculateCoefficientsAtStall(
paddedStallAngleLow, correctedLiftSlope, zeroLiftAoA, stallAngleHigh, stallAngleLow);
lerpParam = (angleOfAttack - stallAngleLow) / (paddedStallAngleLow - stallAngleLow);
}
aerodynamicCoefficients = Vector3.Lerp(aerodynamicCoefficientsLow, aerodynamicCoefficientsStall, lerpParam);
}
}
return aerodynamicCoefficients;
}

private Vector3 CalculateCoefficientsAtLowAoA(float angleOfAttack,
float correctedLiftSlope,
float zeroLiftAoA)
{
float liftCoefficient = correctedLiftSlope * (angleOfAttack - zeroLiftAoA);
float inducedAngle = liftCoefficient / (Mathf.PI * AspectRatio);
float effectiveAngle = angleOfAttack - zeroLiftAoA - inducedAngle;

float tangentialCoefficient = SkinFriction * Mathf.Cos(effectiveAngle);

float normalCoefficient = (liftCoefficient +
Mathf.Sin(effectiveAngle) * tangentialCoefficient) / Mathf.Cos(effectiveAngle);
float dragCoefficient = normalCoefficient * Mathf.Sin(effectiveAngle) + tangentialCoefficient * Mathf.Cos(effectiveAngle);
float torqueCoefficient = -normalCoefficient * TorqCoefficientProportion(effectiveAngle);

return new Vector3(liftCoefficient, dragCoefficient, torqueCoefficient);
}

private Vector3 CalculateCoefficientsAtStall(float angleOfAttack,
float correctedLiftSlope,
float zeroLiftAoA,
float stallAngleHigh,
float stallAngleLow)
{
float liftCoefficientLowAoA;
if (angleOfAttack > stallAngleHigh)
{
liftCoefficientLowAoA = correctedLiftSlope * (stallAngleHigh - zeroLiftAoA);
}
else
{
liftCoefficientLowAoA = correctedLiftSlope * (stallAngleLow - zeroLiftAoA);
}
float inducedAngle = liftCoefficientLowAoA / (Mathf.PI * AspectRatio);

float lerpParam;
if (angleOfAttack > stallAngleHigh)
{
lerpParam = (Mathf.PI / 2 - Mathf.Clamp(angleOfAttack, -Mathf.PI / 2, Mathf.PI / 2))
/ (Mathf.PI / 2 - stallAngleHigh);
}
else
{
lerpParam = (-Mathf.PI / 2 - Mathf.Clamp(angleOfAttack, -Mathf.PI / 2, Mathf.PI / 2))
/ (-Mathf.PI / 2 - stallAngleLow);
}
inducedAngle = Mathf.Lerp(0, inducedAngle, lerpParam);
float effectiveAngle = angleOfAttack - zeroLiftAoA - inducedAngle;

float normalCoefficient = FrictionAt90Degrees(FlapAngle) * Mathf.Sin(effectiveAngle) *
(1 / (0.56f + 0.44f * Mathf.Abs(Mathf.Sin(effectiveAngle))) -
0.41f * (1 - Mathf.Exp(-17 / AspectRatio)));
float tangentialCoefficient = 0.5f * SkinFriction * Mathf.Cos(effectiveAngle);

float liftCoefficient = normalCoefficient * Mathf.Cos(effectiveAngle) - tangentialCoefficient * Mathf.Sin(effectiveAngle);
float dragCoefficient = normalCoefficient * Mathf.Sin(effectiveAngle) + tangentialCoefficient * Mathf.Cos(effectiveAngle);
float torqueCoefficient = -normalCoefficient * TorqCoefficientProportion(effectiveAngle);

return new Vector3(liftCoefficient, dragCoefficient, torqueCoefficient);
}

private float TorqCoefficientProportion(float effectiveAngle)
{
return 0.25f - 0.175f * (1 - 2 * Mathf.Abs(effectiveAngle) / Mathf.PI);
}

private float FrictionAt90Degrees(float flapAngle)
{
return 1.98f - 4.26e-2f * flapAngle * flapAngle + 2.1e-1f * flapAngle;
}

private float FlapEffectivnessCorrection(float flapAngle)
{
return Mathf.Lerp(0.8f, 0.4f, (Mathf.Abs(flapAngle) * Mathf.Rad2Deg - 10) / 50);
}

private float LiftCoefficientMaxFraction(float flapFraction)
{
return Mathf.Clamp01(1 - 0.5f * (flapFraction - 0.1f) / 0.3f);
}
}
}
Binary file modified unity/SlateShipyard/Library/ArtifactDB
Binary file not shown.
18 changes: 9 additions & 9 deletions unity/SlateShipyard/Library/CurrentLayout-default.dwlt
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ MonoBehaviour:
m_MinSize: {x: 679, y: 492}
m_MaxSize: {x: 14002, y: 14042}
vertical: 0
controlID: 47
controlID: 58
--- !u!114 &3
MonoBehaviour:
m_ObjectHideFlags: 52
Expand Down Expand Up @@ -219,7 +219,7 @@ MonoBehaviour:
m_MinSize: {x: 403, y: 492}
m_MaxSize: {x: 10001, y: 14042}
vertical: 1
controlID: 48
controlID: 59
--- !u!114 &10
MonoBehaviour:
m_ObjectHideFlags: 52
Expand All @@ -244,7 +244,7 @@ MonoBehaviour:
m_MinSize: {x: 403, y: 221}
m_MaxSize: {x: 8003, y: 4021}
vertical: 0
controlID: 16
controlID: 60
--- !u!114 &11
MonoBehaviour:
m_ObjectHideFlags: 52
Expand Down Expand Up @@ -502,8 +502,8 @@ MonoBehaviour:
m_SceneHierarchy:
m_TreeViewState:
scrollPos: {x: 0, y: 0}
m_SelectedIDs: 84010000
m_LastClickedID: 0
m_SelectedIDs: 64fbffff
m_LastClickedID: -1180
m_ExpandedIDs: 68fbffff
m_RenameOverlay:
m_UserAcceptedRename: 0
Expand Down Expand Up @@ -564,9 +564,9 @@ MonoBehaviour:
m_PlayAudio: 0
m_AudioPlay: 0
m_Position:
m_Target: {x: 4.228218, y: 2.04314, z: -8.3932495}
m_Target: {x: 4.330412, y: 3.0394883, z: -1.8296437}
speed: 2
m_Value: {x: 4.228218, y: 2.04314, z: -8.3932495}
m_Value: {x: 4.330412, y: 3.0394883, z: -1.8296437}
m_RenderMode: 0
m_CameraMode:
drawMode: 0
Expand Down Expand Up @@ -612,9 +612,9 @@ MonoBehaviour:
m_GridAxis: 1
m_gridOpacity: 0.5
m_Rotation:
m_Target: {x: -0.15175657, y: -0.027582342, z: 0.004208596, w: -0.9880633}
m_Target: {x: -0.12040494, y: 0.33737773, z: -0.043585144, w: -0.93266106}
speed: 2
m_Value: {x: -0.15175657, y: -0.027582344, z: 0.004208596, w: -0.98806334}
m_Value: {x: -0.120334774, y: 0.33876327, z: -0.04376401, w: -0.93211794}
m_Size:
m_Target: 0.727354
speed: 2
Expand Down
Binary file modified unity/SlateShipyard/Library/SourceAssetDB
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"cameraMode":{"drawMode":0,"name":"Shaded","section":"Shading Mode"},"sceneLighting":true,"audioPlay":false,"sceneViewState":{"showFog":true,"showMaterialUpdate":false,"showSkybox":true,"showFlares":true,"showImageEffects":true,"showParticleSystems":true},"in2DMode":false,"pivot":{"x":4.228218078613281,"y":2.043139934539795,"z":-8.39324951171875},"rotation":{"x":-0.15175656974315644,"y":-0.02758234180510044,"z":0.004208595957607031,"w":-0.9880632758140564},"size":0.7273539900779724,"orthographic":false}
{"cameraMode":{"drawMode":0,"name":"Shaded","section":"Shading Mode"},"sceneLighting":true,"audioPlay":false,"sceneViewState":{"showFog":true,"showMaterialUpdate":false,"showSkybox":true,"showFlares":true,"showImageEffects":true,"showParticleSystems":true},"in2DMode":false,"pivot":{"x":4.330411911010742,"y":3.0394883155822756,"z":-1.829643726348877},"rotation":{"x":-0.1204049363732338,"y":0.33737772703170779,"z":-0.043585143983364108,"w":-0.9326610565185547},"size":0.7273539900779724,"orthographic":false}

0 comments on commit 3199492

Please sign in to comment.