mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Reduce abstraction for lift calculation; remove RigidWings struct
This commit is contained in:
parent
96168b5654
commit
7186569259
@ -1,6 +1,6 @@
|
|||||||
use super::{
|
use super::{
|
||||||
body::{object, Body},
|
body::{object, Body},
|
||||||
Density, Ori, Vel,
|
CharacterState, Density, Ori, Vel,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
consts::{AIR_DENSITY, WATER_DENSITY},
|
consts::{AIR_DENSITY, WATER_DENSITY},
|
||||||
@ -90,10 +90,9 @@ impl Default for Fluid {
|
|||||||
impl Body {
|
impl Body {
|
||||||
pub fn aerodynamic_forces(
|
pub fn aerodynamic_forces(
|
||||||
&self,
|
&self,
|
||||||
ori: &Ori,
|
|
||||||
rel_flow: &Vel,
|
rel_flow: &Vel,
|
||||||
fluid_density: f32,
|
fluid_density: f32,
|
||||||
wings: Option<&RigidWings>,
|
character_state: Option<&CharacterState>,
|
||||||
) -> Vec3<f32> {
|
) -> Vec3<f32> {
|
||||||
let v_sq = rel_flow.0.magnitude_squared();
|
let v_sq = rel_flow.0.magnitude_squared();
|
||||||
if v_sq < 0.25 {
|
if v_sq < 0.25 {
|
||||||
@ -104,39 +103,41 @@ impl Body {
|
|||||||
// All the coefficients come pre-multiplied by their reference area
|
// All the coefficients come pre-multiplied by their reference area
|
||||||
0.5 * fluid_density
|
0.5 * fluid_density
|
||||||
* v_sq
|
* v_sq
|
||||||
* wings
|
* character_state
|
||||||
.map(|wings| {
|
.and_then(|cs| match cs {
|
||||||
// Since we have wings, we proceed to calculate the lift and drag
|
CharacterState::Glide(data) => {
|
||||||
|
Some((data.aspect_ratio, data.planform_area, data.ori))
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|(ar, area, ori)| {
|
||||||
|
// We have an elliptical wing; proceed to calculate its lift and drag
|
||||||
|
|
||||||
let ar = wings.aspect_ratio();
|
|
||||||
// aoa will be positive when we're pitched up and negative otherwise
|
// aoa will be positive when we're pitched up and negative otherwise
|
||||||
let aoa = angle_of_attack(ori, &rel_flow_dir);
|
let aoa = angle_of_attack(&ori, &rel_flow_dir);
|
||||||
// c_l will be positive when aoa is positive (we have positive lift,
|
// c_l will be positive when aoa is positive (we have positive lift,
|
||||||
// producing an upward force) and negative otherwise
|
// producing an upward force) and negative otherwise
|
||||||
let c_l = wings.lift_coefficient(aoa);
|
let c_l = lift_coefficient(ar, area, aoa);
|
||||||
|
|
||||||
// lift dir will be orthogonal to the local relative flow vector.
|
// lift dir will be orthogonal to the local relative flow vector.
|
||||||
// Local relative flow is the resulting vector of (relative) freestream flow
|
// Local relative flow is the resulting vector of (relative) freestream
|
||||||
// + downwash (created by the vortices of the wing tips)
|
// flow + downwash (created by the vortices
|
||||||
|
// of the wing tips)
|
||||||
let lift_dir: Dir = {
|
let lift_dir: Dir = {
|
||||||
// induced angle of attack
|
// induced angle of attack
|
||||||
let aoa_i = c_l / (PI * ar);
|
let aoa_i = c_l / (PI * ar);
|
||||||
// effective angle of attack; the aoa as seen by aerofoil after downwash
|
// effective angle of attack; the aoa as seen by aerofoil after
|
||||||
|
// downwash
|
||||||
let aoa_eff = aoa - aoa_i;
|
let aoa_eff = aoa - aoa_i;
|
||||||
/*println!(
|
// Angle between chord line and local relative wind is aoa_eff
|
||||||
"CL={:.1}, α={:.1}°, αᵢ={:.1}°, αₑ={:.1}°, AR={:.1}",
|
// radians. Direction of lift is
|
||||||
c_l,
|
// perpendicular to local relative wind.
|
||||||
aoa.to_degrees(),
|
// At positive lift, local relative wind will be below our cord line
|
||||||
aoa_i.to_degrees(),
|
// at an angle of aoa_eff. Thus if
|
||||||
aoa_eff.to_degrees(),
|
// we pitch down by aoa_eff radians then
|
||||||
ar
|
// our chord line will be colinear with local relative wind vector
|
||||||
);*/
|
// and our up will be the direction
|
||||||
// Angle between chord line and local relative wind is aoa_eff radians.
|
// of lift.
|
||||||
// Direction of lift is perpendicular to local relative wind.
|
|
||||||
// At positive lift, local relative wind will be below our cord line at
|
|
||||||
// an angle of aoa_eff. Thus if we pitch down by aoa_eff radians then
|
|
||||||
// our chord line will be colinear with local relative wind vector and
|
|
||||||
// our up will be the direction of lift.
|
|
||||||
ori.pitched_down(aoa_eff).up()
|
ori.pitched_down(aoa_eff).up()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -146,20 +147,12 @@ impl Body {
|
|||||||
// (this definition should not be used for aspect ratios > 25)
|
// (this definition should not be used for aspect ratios > 25)
|
||||||
let e = 1.78 * (1.0 - 0.045 * ar.powf(0.68)) - 0.64;
|
let e = 1.78 * (1.0 - 0.045 * ar.powf(0.68)) - 0.64;
|
||||||
|
|
||||||
wings.zero_lift_drag_coefficient()
|
zero_lift_drag_coefficient(area)
|
||||||
+ self.parasite_drag_coefficient()
|
+ self.parasite_drag_coefficient()
|
||||||
+ c_l.powi(2) / (PI * e * ar)
|
+ c_l.powi(2) / (PI * e * ar)
|
||||||
};
|
};
|
||||||
debug_assert!(c_d.is_sign_positive());
|
debug_assert!(c_d.is_sign_positive());
|
||||||
debug_assert!(c_l.is_sign_positive() || aoa.is_sign_negative());
|
debug_assert!(c_l.is_sign_positive() || aoa.is_sign_negative());
|
||||||
/*println!(
|
|
||||||
"L/D (at α={:.1}, AR={:.1}) = {:.1}/{:.1} = {:.1}",
|
|
||||||
aoa.to_degrees(),
|
|
||||||
ar,
|
|
||||||
0.5 * fluid_density * v_sq * c_l,
|
|
||||||
0.5 * fluid_density * v_sq * c_d,
|
|
||||||
c_l / c_d
|
|
||||||
);*/
|
|
||||||
|
|
||||||
c_l * *lift_dir + c_d * *rel_flow_dir
|
c_l * *lift_dir + c_d * *rel_flow_dir
|
||||||
})
|
})
|
||||||
@ -192,24 +185,28 @@ impl Body {
|
|||||||
} else {
|
} else {
|
||||||
1.0
|
1.0
|
||||||
};
|
};
|
||||||
cd * std::f32::consts::PI * dim.x * dim.z
|
cd * PI * dim.x * dim.z
|
||||||
},
|
},
|
||||||
|
|
||||||
// Cross-section, zero-lift angle; exclude the wings (width * 0.2)
|
// Cross-section, zero-lift angle; exclude the wings (width * 0.2)
|
||||||
Body::BirdMedium(_) | Body::BirdLarge(_) | Body::Dragon(_) => {
|
Body::BirdMedium(_) | Body::BirdLarge(_) | Body::Dragon(_) => {
|
||||||
let dim = self.dimensions().map(|a| a * 0.5);
|
let dim = self.dimensions().map(|a| a * 0.5);
|
||||||
|
// "Field Estimates of Body Drag Coefficient on the Basis of Dives in Passerine
|
||||||
|
// Birds", Anders Hedenström and Felix Liechti, 2001
|
||||||
let cd = match self {
|
let cd = match self {
|
||||||
Body::BirdMedium(_) => 0.2,
|
Body::BirdLarge(_) | Body::BirdMedium(_) => 0.2,
|
||||||
Body::BirdLarge(_) => 0.4,
|
// arbitrary
|
||||||
_ => 0.7,
|
_ => 0.7,
|
||||||
};
|
};
|
||||||
cd * std::f32::consts::PI * dim.x * 0.2 * dim.z
|
cd * PI * dim.x * 0.2 * dim.z
|
||||||
},
|
},
|
||||||
|
|
||||||
// Cross-section, zero-lift angle; exclude the fins (width * 0.2)
|
// Cross-section, zero-lift angle; exclude the fins (width * 0.2)
|
||||||
Body::FishMedium(_) | Body::FishSmall(_) => {
|
Body::FishMedium(_) | Body::FishSmall(_) => {
|
||||||
let dim = self.dimensions().map(|a| a * 0.5);
|
let dim = self.dimensions().map(|a| a * 0.5);
|
||||||
0.031 * std::f32::consts::PI * dim.x * 0.2 * dim.z
|
// "A Simple Method to Determine Drag Coefficients in Aquatic Animals",
|
||||||
|
// D. Bilo and W. Nachtigall, 1980
|
||||||
|
0.031 * PI * dim.x * 0.2 * dim.z
|
||||||
},
|
},
|
||||||
|
|
||||||
Body::Object(object) => match object {
|
Body::Object(object) => match object {
|
||||||
@ -225,7 +222,7 @@ impl Body {
|
|||||||
| object::Body::FireworkYellow
|
| object::Body::FireworkYellow
|
||||||
| object::Body::MultiArrow => {
|
| object::Body::MultiArrow => {
|
||||||
let dim = self.dimensions().map(|a| a * 0.5);
|
let dim = self.dimensions().map(|a| a * 0.5);
|
||||||
0.02 * std::f32::consts::PI * dim.x * dim.z
|
0.02 * PI * dim.x * dim.z
|
||||||
},
|
},
|
||||||
|
|
||||||
// spherical-ish objects
|
// spherical-ish objects
|
||||||
@ -243,12 +240,12 @@ impl Body {
|
|||||||
| object::Body::Pumpkin4
|
| object::Body::Pumpkin4
|
||||||
| object::Body::Pumpkin5 => {
|
| object::Body::Pumpkin5 => {
|
||||||
let dim = self.dimensions().map(|a| a * 0.5);
|
let dim = self.dimensions().map(|a| a * 0.5);
|
||||||
0.5 * std::f32::consts::PI * dim.x * dim.z
|
0.5 * PI * dim.x * dim.z
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
let dim = self.dimensions();
|
let dim = self.dimensions();
|
||||||
2.0 * (std::f32::consts::PI / 6.0 * dim.x * dim.y * dim.z).powf(2.0 / 3.0)
|
2.0 * (PI / 6.0 * dim.x * dim.y * dim.z).powf(2.0 / 3.0)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -256,7 +253,7 @@ impl Body {
|
|||||||
// Airships tend to use the square of the cube root of its volume for
|
// Airships tend to use the square of the cube root of its volume for
|
||||||
// reference area
|
// reference area
|
||||||
let dim = self.dimensions();
|
let dim = self.dimensions();
|
||||||
(std::f32::consts::PI / 6.0 * dim.x * dim.y * dim.z).powf(2.0 / 3.0)
|
(PI / 6.0 * dim.x * dim.y * dim.z).powf(2.0 / 3.0)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -267,56 +264,21 @@ fn angle_of_attack(ori: &Ori, rel_flow_dir: &Dir) -> f32 {
|
|||||||
PI / 2.0 - ori.up().angle_between(rel_flow_dir.to_vec())
|
PI / 2.0 - ori.up().angle_between(rel_flow_dir.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An elliptical fixed rigid wing. Plurally named simply because it's a shape
|
|
||||||
/// typically composed of two wings forming an elliptical lift distribution.
|
|
||||||
//
|
|
||||||
// Animal wings are technically flexible, not rigid, (difference being that the
|
|
||||||
// former's shape is affected by the flow) and usually has the ability to
|
|
||||||
// assume complex shapes with properties like curved camber line, span-wise
|
|
||||||
// twist, dihedral angle, sweep angle, and partitioned sections. However, we
|
|
||||||
// could make do with this model for fully extended animal wings, enabling them
|
|
||||||
// to glide.
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct RigidWings {
|
|
||||||
aspect_ratio: f32,
|
|
||||||
planform_area: f32,
|
|
||||||
// sweep_angle: Option<f32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RigidWings {
|
|
||||||
/// Wings from total span (wing-tip to wing-tip) and
|
|
||||||
/// chord length (leading edge to trailing edge)
|
|
||||||
pub fn new(span_length: f32, chord_length: f32) -> Self {
|
|
||||||
let planform_area = std::f32::consts::PI * chord_length * span_length * 0.25;
|
|
||||||
Self {
|
|
||||||
aspect_ratio: span_length.powi(2) / planform_area,
|
|
||||||
planform_area,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The aspect ratio is the ratio of the span squared to actual planform
|
|
||||||
/// area
|
|
||||||
pub fn aspect_ratio(&self) -> f32 { self.aspect_ratio }
|
|
||||||
|
|
||||||
pub fn planform_area(&self) -> f32 { self.planform_area }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RigidWings {
|
|
||||||
/// Total lift coefficient for a finite wing of symmetric aerofoil shape and
|
/// Total lift coefficient for a finite wing of symmetric aerofoil shape and
|
||||||
/// elliptical pressure distribution.
|
/// elliptical pressure distribution.
|
||||||
pub fn lift_coefficient(&self, aoa: f32) -> f32 {
|
pub fn lift_coefficient(aspect_ratio: f32, planform_area: f32, aoa: f32) -> f32 {
|
||||||
let aoa_abs = aoa.abs();
|
let aoa_abs = aoa.abs();
|
||||||
let stall_angle = PI * 0.1;
|
let stall_angle = PI * 0.1;
|
||||||
inline_tweak::tweak!(1.0)
|
inline_tweak::tweak!(1.0)
|
||||||
* self.planform_area()
|
* planform_area
|
||||||
* if aoa_abs < stall_angle {
|
* if aoa_abs < stall_angle {
|
||||||
self.lift_slope(None) * aoa
|
lift_slope(aspect_ratio, None) * aoa
|
||||||
} else if inline_tweak::tweak!(true) {
|
} else if inline_tweak::tweak!(true) {
|
||||||
// This is when flow separation and turbulence starts to kick in.
|
// This is when flow separation and turbulence starts to kick in.
|
||||||
// Going to just make something up (based on some data), as the alternative is
|
// Going to just make something up (based on some data), as the alternative is
|
||||||
// to just throw your hands up and return 0
|
// to just throw your hands up and return 0
|
||||||
let aoa_s = aoa.signum();
|
let aoa_s = aoa.signum();
|
||||||
let c_l_max = self.lift_slope(None) * stall_angle;
|
let c_l_max = lift_slope(aspect_ratio, None) * stall_angle;
|
||||||
let deg_45 = PI / 4.0;
|
let deg_45 = PI / 4.0;
|
||||||
if aoa_abs < deg_45 {
|
if aoa_abs < deg_45 {
|
||||||
// drop directly to 0.6 * max lift at stall angle
|
// drop directly to 0.6 * max lift at stall angle
|
||||||
@ -333,56 +295,42 @@ impl RigidWings {
|
|||||||
|
|
||||||
/// The zero-lift profile drag coefficient is the parasite drag on the wings
|
/// The zero-lift profile drag coefficient is the parasite drag on the wings
|
||||||
/// at the angle of attack which generates no lift
|
/// at the angle of attack which generates no lift
|
||||||
pub fn zero_lift_drag_coefficient(&self) -> f32 {
|
pub fn zero_lift_drag_coefficient(planform_area: f32) -> f32 {
|
||||||
// avg value for Harris' hawk (Parabuteo unicinctus) [1]
|
// avg value for Harris' hawk (Parabuteo unicinctus) [1]
|
||||||
self.planform_area() * 0.02
|
planform_area * 0.02
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The change in lift over change in angle of attack¹. Multiplying by angle
|
/// The change in lift over change in angle of attack¹. Multiplying by angle
|
||||||
/// of attack gives the lift coefficient (for a finite wing, not aerofoil).
|
/// of attack gives the lift coefficient (for a finite wing, not aerofoil).
|
||||||
///
|
|
||||||
/// Aspect ratio is the ratio of total wing span squared over planform area.
|
/// Aspect ratio is the ratio of total wing span squared over planform area.
|
||||||
///
|
///
|
||||||
/// # Notes
|
/// # Notes
|
||||||
///
|
|
||||||
/// Only valid for symmetric, elliptical wings at small² angles of attack³.
|
/// Only valid for symmetric, elliptical wings at small² angles of attack³.
|
||||||
/// Does not apply to twisted, cambered or delta wings. (It still gives a
|
/// Does not apply to twisted, cambered or delta wings. (It still gives a
|
||||||
/// reasonably accurate approximation if the wing shape is not truly
|
/// reasonably accurate approximation if the wing shape is not truly
|
||||||
/// elliptical.)
|
/// elliptical.)
|
||||||
///
|
|
||||||
/// 1. geometric angle of attack, i.e. the pitch angle relative to
|
/// 1. geometric angle of attack, i.e. the pitch angle relative to
|
||||||
/// freestream flow
|
/// freestream flow
|
||||||
/// 2. up to around ~18°, at which point maximum lift has been achieved and
|
/// 2. up to around ~18°, at which point maximum lift has been achieved and
|
||||||
/// thereafter falls precipitously, causing a stall (this is the stall
|
/// thereafter falls precipitously, causing a stall (this is the stall
|
||||||
/// angle) 3. effective aoa, i.e. geometric aoa - induced aoa; assumes
|
/// angle) 3. effective aoa, i.e. geometric aoa - induced aoa; assumes
|
||||||
/// no sideslip
|
/// no sideslip
|
||||||
fn lift_slope(&self, sweep_angle: Option<f32>) -> f32 {
|
fn lift_slope(aspect_ratio: f32, sweep_angle: Option<f32>) -> f32 {
|
||||||
// lift slope for a thin aerofoil, given by Thin Aerofoil Theory
|
// lift slope for a thin aerofoil, given by Thin Aerofoil Theory
|
||||||
let ar = self.aspect_ratio();
|
|
||||||
let a0 = 2.0 * PI;
|
let a0 = 2.0 * PI;
|
||||||
if let Some(sweep) = sweep_angle {
|
if let Some(sweep) = sweep_angle {
|
||||||
// for swept wings we use Kuchemann's modification to Helmbold's
|
// for swept wings we use Kuchemann's modification to Helmbold's
|
||||||
// equation
|
// equation
|
||||||
let a0_cos_sweep = a0 * sweep.cos();
|
let a0_cos_sweep = a0 * sweep.cos();
|
||||||
let x = a0_cos_sweep / (PI * ar);
|
let x = a0_cos_sweep / (PI * aspect_ratio);
|
||||||
a0_cos_sweep / ((1.0 + x.powi(2)).sqrt() + x)
|
a0_cos_sweep / ((1.0 + x.powi(2)).sqrt() + x)
|
||||||
} else if ar < 4.0 {
|
} else if aspect_ratio < 4.0 {
|
||||||
// for low aspect ratio wings (AR < 4) we use Helmbold's equation
|
// for low aspect ratio wings (AR < 4) we use Helmbold's equation
|
||||||
let x = a0 / (PI * ar);
|
let x = a0 / (PI * aspect_ratio);
|
||||||
a0 / ((1.0 + x.powi(2)).sqrt() + x)
|
a0 / ((1.0 + x.powi(2)).sqrt() + x)
|
||||||
} else {
|
} else {
|
||||||
// for high aspect ratio wings (AR > 4) we use the equation given by
|
// for high aspect ratio wings (AR > 4) we use the equation given by
|
||||||
// Prandtl's lifting-line theory
|
// Prandtl's lifting-line theory
|
||||||
a0 / (1.0 + (a0 / (PI * ar)))
|
a0 / (1.0 + (a0 / (PI * aspect_ratio)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
## References:
|
|
||||||
|
|
||||||
1. "Field Estimates of Body Drag Coefficient on the Basis of Dives in Passerine Birds",
|
|
||||||
Anders Hedenström and Felix Liechti, 2001
|
|
||||||
2. "A Simple Method to Determine Drag Coefficients in Aquatic Animals",
|
|
||||||
D. Bilo and W. Nachtigall, 1980
|
|
||||||
*/
|
|
||||||
|
@ -68,7 +68,7 @@ pub use self::{
|
|||||||
InputKind, InventoryAction, InventoryEvent, InventoryManip, MountState, Mounting,
|
InputKind, InventoryAction, InventoryEvent, InventoryManip, MountState, Mounting,
|
||||||
},
|
},
|
||||||
energy::{Energy, EnergyChange, EnergySource},
|
energy::{Energy, EnergyChange, EnergySource},
|
||||||
fluid_dynamics::{Fluid, RigidWings},
|
fluid_dynamics::Fluid,
|
||||||
group::Group,
|
group::Group,
|
||||||
home_chunk::HomeChunk,
|
home_chunk::HomeChunk,
|
||||||
inputs::CanBuild,
|
inputs::CanBuild,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::utils::handle_climb;
|
use super::utils::handle_climb;
|
||||||
use crate::{
|
use crate::{
|
||||||
comp::{inventory::slot::EquipSlot, CharacterState, Ori, RigidWings, StateUpdate},
|
comp::{inventory::slot::EquipSlot, CharacterState, Ori, StateUpdate},
|
||||||
states::behavior::{CharacterBehavior, JoinData},
|
states::behavior::{CharacterBehavior, JoinData},
|
||||||
util::Dir,
|
util::Dir,
|
||||||
};
|
};
|
||||||
@ -9,14 +9,19 @@ use vek::*;
|
|||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
pub wings: RigidWings,
|
/// The aspect ratio is the ratio of the span squared to actual planform
|
||||||
|
/// area
|
||||||
|
pub aspect_ratio: f32,
|
||||||
|
pub planform_area: f32,
|
||||||
pub ori: Ori,
|
pub ori: Ori,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Data {
|
impl Data {
|
||||||
pub fn new(span_length: f32, chord_length: f32, ori: Ori) -> Self {
|
pub fn new(span_length: f32, chord_length: f32, ori: Ori) -> Self {
|
||||||
|
let planform_area = std::f32::consts::PI * chord_length * span_length * 0.25;
|
||||||
Self {
|
Self {
|
||||||
wings: RigidWings::new(span_length, chord_length),
|
aspect_ratio: span_length.powi(2) / planform_area,
|
||||||
|
planform_area,
|
||||||
ori,
|
ori,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ use common::{
|
|||||||
event::{EventBus, ServerEvent},
|
event::{EventBus, ServerEvent},
|
||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
resources::DeltaTime,
|
resources::DeltaTime,
|
||||||
states,
|
|
||||||
terrain::{Block, TerrainGrid},
|
terrain::{Block, TerrainGrid},
|
||||||
uid::Uid,
|
uid::Uid,
|
||||||
util::{Projection, SpatialGrid},
|
util::{Projection, SpatialGrid},
|
||||||
@ -43,7 +42,6 @@ fn fluid_density(height: f32, fluid: &Fluid) -> Density {
|
|||||||
fn integrate_forces(
|
fn integrate_forces(
|
||||||
dt: &DeltaTime,
|
dt: &DeltaTime,
|
||||||
mut vel: Vel,
|
mut vel: Vel,
|
||||||
ori: &Ori,
|
|
||||||
body: &Body,
|
body: &Body,
|
||||||
density: &Density,
|
density: &Density,
|
||||||
mass: &Mass,
|
mass: &Mass,
|
||||||
@ -61,17 +59,7 @@ fn integrate_forces(
|
|||||||
// Aerodynamic/hydrodynamic forces
|
// Aerodynamic/hydrodynamic forces
|
||||||
if !rel_flow.0.is_approx_zero() {
|
if !rel_flow.0.is_approx_zero() {
|
||||||
debug_assert!(!rel_flow.0.map(|a| a.is_nan()).reduce_or());
|
debug_assert!(!rel_flow.0.map(|a| a.is_nan()).reduce_or());
|
||||||
let glider: Option<&states::glide::Data> = character_state.and_then(|cs| match cs {
|
let impulse = dt.0 * body.aerodynamic_forces(&rel_flow, fluid_density.0, character_state);
|
||||||
CharacterState::Glide(data) => Some(data),
|
|
||||||
_ => None,
|
|
||||||
});
|
|
||||||
let impulse = dt.0
|
|
||||||
* body.aerodynamic_forces(
|
|
||||||
glider.map(|g| &g.ori).unwrap_or(ori),
|
|
||||||
&rel_flow,
|
|
||||||
fluid_density.0,
|
|
||||||
glider.map(|g| g.wings).as_ref(),
|
|
||||||
);
|
|
||||||
debug_assert!(!impulse.map(|a| a.is_nan()).reduce_or());
|
debug_assert!(!impulse.map(|a| a.is_nan()).reduce_or());
|
||||||
if !impulse.is_approx_zero() {
|
if !impulse.is_approx_zero() {
|
||||||
let new_v = vel.0 + impulse / mass.0;
|
let new_v = vel.0 + impulse / mass.0;
|
||||||
@ -576,7 +564,6 @@ impl<'a> PhysicsData<'a> {
|
|||||||
(
|
(
|
||||||
positions,
|
positions,
|
||||||
velocities,
|
velocities,
|
||||||
&write.orientations,
|
|
||||||
read.stickies.maybe(),
|
read.stickies.maybe(),
|
||||||
&read.bodies,
|
&read.bodies,
|
||||||
read.character_states.maybe(),
|
read.character_states.maybe(),
|
||||||
@ -595,7 +582,6 @@ impl<'a> PhysicsData<'a> {
|
|||||||
(
|
(
|
||||||
pos,
|
pos,
|
||||||
vel,
|
vel,
|
||||||
ori,
|
|
||||||
sticky,
|
sticky,
|
||||||
body,
|
body,
|
||||||
character_state,
|
character_state,
|
||||||
@ -627,7 +613,6 @@ impl<'a> PhysicsData<'a> {
|
|||||||
vel.0 = integrate_forces(
|
vel.0 = integrate_forces(
|
||||||
&dt,
|
&dt,
|
||||||
*vel,
|
*vel,
|
||||||
ori,
|
|
||||||
body,
|
body,
|
||||||
density,
|
density,
|
||||||
mass,
|
mass,
|
||||||
|
Loading…
Reference in New Issue
Block a user