Glider vortices PoC particle effects

This commit is contained in:
Ludvig Böklin 2021-06-22 19:56:05 +02:00
parent 34d264c413
commit 07dda3be22
5 changed files with 102 additions and 6 deletions

View File

@ -72,6 +72,7 @@ const int WATER = 30;
const int ICE_SPIKES = 31; const int ICE_SPIKES = 31;
const int DRIP = 32; const int DRIP = 32;
const int TORNADO = 33; const int TORNADO = 33;
const int VORTEX = 34;
// meters per second squared (acceleration) // meters per second squared (acceleration)
const float earth_gravity = 9.807; const float earth_gravity = 9.807;
@ -553,6 +554,29 @@ void main() {
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9) spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
); );
break; break;
case VORTEX:
f_reflect = 1.0;
float mag = length(inst_dir);
float s = 4 * start_end(max(0, slow_start(2.0) - 0.3), 0);
float r = 0.2 * (pow(1 * rand0, 2) + pow(rand1 * 2, 2) + pow(rand2 * 4, 2));
attr = Attr(
spiral_motion(
s * normalize(inst_dir) * mag,
0.5 * max(0, slow_start(2.0) - 0.3) * max(0, floor(0.5 * r - 0.5)) * min(linear_scale(10), 1),
lifetime / (20.0 * inst_lifespan),
0.4 * r,
1.1 * inst_time * (length(inst_dir))
),
vec3(
(1.0 - 0.5 * abs(r))
* (1.5 + 0.5 * sin(tick.x * 10 - lifetime * 10))
* max(0, mag - 12) * s
* 0.02
),
vec4(vec3(1, 1, 1), 1),
spin_in_axis(inst_dir, tick.z)
);
break;
default: default:
attr = Attr( attr = Attr(
linear_motion( linear_motion(

View File

@ -232,7 +232,7 @@ pub fn angle_of_attack(ori: &Ori, rel_flow_dir: &Dir) -> f32 {
/// 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. (Multiplied by reference area.) /// elliptical pressure distribution. (Multiplied by reference area.)
fn lift_coefficient( pub fn lift_coefficient(
planform_area: f32, planform_area: f32,
angle_of_attack: f32, angle_of_attack: f32,
lift_slope: f32, lift_slope: f32,
@ -355,7 +355,7 @@ impl WingShape {
} }
/// Induced drag coefficient (drag due to lift) /// Induced drag coefficient (drag due to lift)
fn induced_drag_coefficient(aspect_ratio: f32, lift_coefficient: f32) -> f32 { pub fn induced_drag_coefficient(aspect_ratio: f32, lift_coefficient: f32) -> f32 {
let ar = aspect_ratio; let ar = aspect_ratio;
if ar > 25.0 { if ar > 25.0 {
tracing::warn!( tracing::warn!(

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
comp::{ comp::{
fluid_dynamics::{Drag, Glide, WingShape}, fluid_dynamics::{Drag, Glide, WingShape},
Ori, Body, Ori, Pos,
}, },
util::Dir, util::Dir,
}; };
@ -17,6 +17,7 @@ pub struct Glider {
pub wing_shape: WingShape, pub wing_shape: WingShape,
pub planform_area: f32, pub planform_area: f32,
pub ori: Ori, pub ori: Ori,
span_length: f32,
} }
impl Glider { impl Glider {
@ -32,10 +33,24 @@ impl Glider {
Self { Self {
wing_shape: WingShape::Elliptical { aspect_ratio }, wing_shape: WingShape::Elliptical { aspect_ratio },
planform_area, planform_area,
span_length,
ori, ori,
} }
} }
pub fn pos(&self, pilot: (&Pos, &Ori, &Body)) -> Pos {
let height = pilot.2.dimensions().z;
let cg = Vec3::unit_z() * height * tweak!(0.7);
let pos_from_cg = *pilot.1.up() * height * tweak!(0.5);
Pos(pilot.0.0 + cg + pos_from_cg)
}
pub fn wing_tips(&self, pilot: (&Pos, &Ori, &Body)) -> (Pos, Pos) {
let right = tweak!(0.65) * *self.ori.right() * self.span_length / 2.0;
let pos = self.pos(pilot).0;
(Pos(pos - right), Pos(pos + right))
}
pub fn roll(&mut self, angle_right: f32) { self.ori = self.ori.rolled_right(angle_right); } pub fn roll(&mut self, angle_right: f32) { self.ori = self.ori.rolled_right(angle_right); }
pub fn pitch(&mut self, angle_up: f32) { self.ori = self.ori.pitched_up(angle_up); } pub fn pitch(&mut self, angle_up: f32) { self.ori = self.ori.pitched_up(angle_up); }

View File

@ -84,6 +84,7 @@ pub enum ParticleMode {
IceSpikes = 31, IceSpikes = 31,
Drip = 32, Drip = 32,
Tornado = 33, Tornado = 33,
Vortex = 34,
} }
impl ParticleMode { impl ParticleMode {

View File

@ -9,8 +9,10 @@ use crate::{
use common::{ use common::{
assets::{AssetExt, DotVoxAsset}, assets::{AssetExt, DotVoxAsset},
comp::{ comp::{
self, aura, beam, body, buff, item::Reagent, object, shockwave, BeamSegment, Body, self, aura, beam, body, buff,
CharacterState, Ori, Pos, Shockwave, Vel, fluid_dynamics::{angle_of_attack, induced_drag_coefficient, lift_coefficient, Glide},
item::Reagent,
object, shockwave, BeamSegment, Body, CharacterState, Ori, Pos, Shockwave, Vel,
}, },
figure::Segment, figure::Segment,
outcome::Outcome, outcome::Outcome,
@ -18,6 +20,7 @@ use common::{
spiral::Spiral2d, spiral::Spiral2d,
states::{self, utils::StageSection}, states::{self, utils::StageSection},
terrain::TerrainChunk, terrain::TerrainChunk,
util::Dir,
vol::{RectRasterableVol, SizedVol}, vol::{RectRasterableVol, SizedVol},
}; };
use common_base::span; use common_base::span;
@ -561,16 +564,69 @@ impl ParticleMgr {
let dt = scene_data.state.get_delta_time(); let dt = scene_data.state.get_delta_time();
let mut rng = thread_rng(); let mut rng = thread_rng();
for (entity, pos, vel, character_state, body) in ( for (entity, pos, vel, ori, character_state, body) in (
&ecs.entities(), &ecs.entities(),
&ecs.read_storage::<Pos>(), &ecs.read_storage::<Pos>(),
ecs.read_storage::<Vel>().maybe(), ecs.read_storage::<Vel>().maybe(),
&ecs.read_storage::<Ori>(),
&ecs.read_storage::<CharacterState>(), &ecs.read_storage::<CharacterState>(),
&ecs.read_storage::<Body>(), &ecs.read_storage::<Body>(),
) )
.join() .join()
{ {
match character_state { match character_state {
CharacterState::Glide(data) => {
let trail_tick_count =
33.max(self.scheduler.heartbeats(Duration::from_millis(1)));
let trail = ecs
.read_storage::<comp::PhysicsState>()
.get(entity)
.and_then(|physics| physics.in_fluid)
.and_then(|fluid| {
vel.map(|vel| (fluid.dynamic_pressure(vel), fluid.relative_flow(vel)))
})
.and_then(|(q, rel_flow)| {
Some(rel_flow.0.magnitude_squared())
.filter(|v_sq| v_sq > &std::f32::EPSILON)
.map(|v_sq| (q, Dir::new(rel_flow.0 / v_sq.sqrt())))
})
.map(|(q, flow_dir)| {
// hacky heuristic for vortex trails; they're nowhere near an accurate
// representation, but
// - it's sort of the right direction
// - it scales with induced drag (which is due to these vortices)
let wing_shape = data.glider.wing_shape();
let aoa = angle_of_attack(data.glider.ori(), &flow_dir);
let c_l = lift_coefficient(
data.glider.planform_area(),
aoa,
wing_shape.lift_slope(),
wing_shape.stall_angle(),
);
let c_d_i = induced_drag_coefficient(wing_shape.aspect_ratio(), c_l);
-q * *data.glider.ori().look_dir() * c_d_i.abs()
})
.unwrap_or_default();
self.particles.reserve(trail_tick_count as usize);
for i in 0..trail_tick_count {
let (left_tip, right_tip) = data.glider.wing_tips((pos, ori, body));
self.particles.push(Particle::new_directed(
Duration::from_millis(300),
time + i as f64 / 1000.0,
ParticleMode::Vortex,
left_tip.0,
left_tip.0 + trail * 0.2,
));
self.particles.push(Particle::new_directed(
Duration::from_millis(300),
time + i as f64 / 1000.0,
ParticleMode::Vortex,
right_tip.0,
right_tip.0 + trail * 0.2,
));
}
},
CharacterState::Boost(_) => { CharacterState::Boost(_) => {
self.particles.resize_with( self.particles.resize_with(
self.particles.len() self.particles.len()