mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-03 12:00:22 +01:00
Let the smoke leave the exhaust as a widening jet that fades in
This commit is contained in:
@@ -274,6 +274,10 @@ are no longer loaded.
|
|||||||
of a particle goes over to `v` (straight up or down, besides the drift with the wind), the faster the larger `drag: d`
|
of a particle goes over to `v` (straight up or down, besides the drift with the wind), the faster the larger `drag: d`
|
||||||
(per second, default 1: about 63% of the way in a second). It takes the place of the old rules of the rise (slower in
|
(per second, default 1: about 63% of the way in a second). It takes the place of the old rules of the rise (slower in
|
||||||
cold and humid air); a template without it behaves as before. The particles don't stop at the ground.
|
cold and humid air); a template without it behaves as before. The particles don't stop at the ground.
|
||||||
|
Two more keys make the smoke come out of the exhaust as a jet instead of puffs swelling above it: `spread: s` — the
|
||||||
|
particles grow by `s` metres of size for each metre they go through the air (a jet widens by about 0.3–0.5 per metre),
|
||||||
|
on top of `size_change`, so they leave the exhaust as small as `min_size`/`max_size` (the size of the pipe) and widen
|
||||||
|
as they rise; `fade_in: t` — they take `t` seconds to show up after they're born, instead of popping up at full opacity.
|
||||||
- **Rain and snow** are particles in three boxes around the camera (10, 24 and 60 metres), more of them the heavier the
|
- **Rain and snow** are particles in three boxes around the camera (10, 24 and 60 metres), more of them the heavier the
|
||||||
rain or snow (the overcast above 1). The drops and flakes fall, drift with the wind, the flakes flutter, and each is
|
rain or snow (the overcast above 1). The drops and flakes fall, drift with the wind, the flakes flutter, and each is
|
||||||
drawn as a streak of its motion against the camera: they slant when the train moves. They are lit like the smoke, so the
|
drawn as a streak of its motion against the camera: they slant when the train moves. They are lit like the smoke, so the
|
||||||
|
|||||||
@@ -246,10 +246,10 @@ void opengl46_gpu_particles::simulate_smoke(particle_manager &Particles, glm::dv
|
|||||||
record.previous = glm::vec4{glm::vec3{state.previous - m_origin}, 0.f};
|
record.previous = glm::vec4{glm::vec3{state.previous - m_origin}, 0.f};
|
||||||
record.launch = glm::vec4{state.inclination[0], state.inclination[1], state.velocity[0], state.velocity[1]};
|
record.launch = glm::vec4{state.inclination[0], state.inclination[1], state.velocity[0], state.velocity[1]};
|
||||||
record.initial = glm::vec4{state.size[0], state.size[1], state.opacity[0], state.opacity[1]};
|
record.initial = glm::vec4{state.size[0], state.size[1], state.opacity[0], state.opacity[1]};
|
||||||
record.sizechange = glm::vec4{state.sizechange[0], state.sizechange[1], state.sizechange[2], 0.f};
|
record.sizechange = glm::vec4{state.sizechange[0], state.sizechange[1], state.sizechange[2], state.spread};
|
||||||
record.opacitychange = glm::vec4{state.opacitychange[0], state.opacitychange[1], state.opacitychange[2], 0.f};
|
record.opacitychange = glm::vec4{state.opacitychange[0], state.opacitychange[1], state.opacitychange[2], 0.f};
|
||||||
record.motion = glm::vec4{state.rise, state.damping, state.risemin, 0.f};
|
record.motion = glm::vec4{state.rise, state.damping, state.risemin, 0.f};
|
||||||
record.settling = glm::vec4{state.settling, state.drag, state.settles ? 1.f : 0.f, 0.f};
|
record.settling = glm::vec4{state.settling, state.drag, state.settles ? 1.f : 0.f, state.fadein};
|
||||||
record.color = glm::vec4{glm::clamp(state.color, glm::vec3{0.f}, glm::vec3{1.f}), 0.f};
|
record.color = glm::vec4{glm::clamp(state.color, glm::vec3{0.f}, glm::vec3{1.f}), 0.f};
|
||||||
record.oldcolor = glm::vec4{glm::clamp(state.color * oldlight, glm::vec3{0.f}, glm::vec3{1.f}), 0.f};
|
record.oldcolor = glm::vec4{glm::clamp(state.color * oldlight, glm::vec3{0.f}, glm::vec3{1.f}), 0.f};
|
||||||
if (pool.size > 0)
|
if (pool.size > 0)
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ opengl46_particles::update( opengl_camera const &Camera ) {
|
|||||||
vertex.color[ 0 ] = particlecolor.r;
|
vertex.color[ 0 ] = particlecolor.r;
|
||||||
vertex.color[ 1 ] = particlecolor.g;
|
vertex.color[ 1 ] = particlecolor.g;
|
||||||
vertex.color[ 2 ] = particlecolor.b;
|
vertex.color[ 2 ] = particlecolor.b;
|
||||||
vertex.color.a = std::clamp(particle.opacity, 0.0f, 1.0f);
|
vertex.color.a = std::clamp(particle.opacity, 0.0f, 1.0f) * sourcedata.fade_in(particle.age);
|
||||||
|
|
||||||
auto const offset { glm::vec3{ particle.position - Camera.position() } };
|
auto const offset { glm::vec3{ particle.position - Camera.position() } };
|
||||||
auto const rotation { glm::angleAxis( particle.rotation, glm::vec3{ 0.f, 0.f, 1.f } ) };
|
auto const rotation { glm::angleAxis( particle.rotation, glm::vec3{ 0.f, 0.f, 1.f } ) };
|
||||||
|
|||||||
@@ -122,6 +122,12 @@ smoke_source::deserialize_mapping( cParser &Input ) {
|
|||||||
else if( key == "drag:" ) {
|
else if( key == "drag:" ) {
|
||||||
m_drag = std::max( 0.f, Input.getToken<float>( true, "\n\r\t ,;[]" ) );
|
m_drag = std::max( 0.f, Input.getToken<float>( true, "\n\r\t ,;[]" ) );
|
||||||
}
|
}
|
||||||
|
else if( key == "spread:" ) {
|
||||||
|
m_spread = std::max( 0.f, Input.getToken<float>( true, "\n\r\t ,;[]" ) );
|
||||||
|
}
|
||||||
|
else if( key == "fade_in:" ) {
|
||||||
|
m_fadein = std::max( 0.f, Input.getToken<float>( true, "\n\r\t ,;[]" ) );
|
||||||
|
}
|
||||||
|
|
||||||
return true; // return value marks a [ key: value ] pair was extracted, nothing about whether it's recognized
|
return true; // return value marks a [ key: value ] pair was extracted, nothing about whether it's recognized
|
||||||
}
|
}
|
||||||
@@ -385,6 +391,10 @@ smoke_source::update( smoke_particle &Particle, bounding_box &Boundingbox, doubl
|
|||||||
if( Particle.opacity <= 0.f ) { return false; }
|
if( Particle.opacity <= 0.f ) { return false; }
|
||||||
// ... otherwise proceed with full update
|
// ... otherwise proceed with full update
|
||||||
m_sizemodifier.update( Particle.size, Timedelta );
|
m_sizemodifier.update( Particle.size, Timedelta );
|
||||||
|
if( m_spread > 0.f ) {
|
||||||
|
// the jet widens with the way it goes
|
||||||
|
Particle.size = std::min( Particle.size + m_spread * glm::length( Particle.velocity ) * static_cast<float>( Timedelta ), m_sizemodifier.limit( value_limit::max ) );
|
||||||
|
}
|
||||||
|
|
||||||
if( m_settles ) {
|
if( m_settles ) {
|
||||||
// the drag of the air takes the particle towards the velocity it settles at
|
// the drag of the air takes the particle towards the velocity it settles at
|
||||||
@@ -463,6 +473,8 @@ smoke_source::update_gpu( double const Timedelta, bool const Onlydespawn ) {
|
|||||||
m_gpu.damping = static_cast<float>( 0.050 * Global.Overcast );
|
m_gpu.damping = static_cast<float>( 0.050 * Global.Overcast );
|
||||||
m_gpu.risemin = static_cast<float>( 0.25 * ( 2.f - Global.Overcast ) );
|
m_gpu.risemin = static_cast<float>( 0.25 * ( 2.f - Global.Overcast ) );
|
||||||
}
|
}
|
||||||
|
m_gpu.spread = m_spread;
|
||||||
|
m_gpu.fadein = m_fadein;
|
||||||
m_gpu.settles = m_settles;
|
m_gpu.settles = m_settles;
|
||||||
m_gpu.settling = m_settling;
|
m_gpu.settling = m_settling;
|
||||||
m_gpu.drag = m_drag;
|
m_gpu.drag = m_drag;
|
||||||
|
|||||||
@@ -105,6 +105,8 @@ public:
|
|||||||
bool settles { false };
|
bool settles { false };
|
||||||
float settling { 0.f };
|
float settling { 0.f };
|
||||||
float drag { 1.f };
|
float drag { 1.f };
|
||||||
|
float spread { 0.f }; // see smoke_source::m_spread
|
||||||
|
float fadein { 0.f }; // see smoke_source::m_fadein
|
||||||
glm::vec3 color { 0.f };
|
glm::vec3 color { 0.f };
|
||||||
};
|
};
|
||||||
// methods
|
// methods
|
||||||
@@ -128,6 +130,12 @@ public:
|
|||||||
std::size_t
|
std::size_t
|
||||||
max_particles() const {
|
max_particles() const {
|
||||||
return m_max_particles; }
|
return m_max_particles; }
|
||||||
|
// share of the opacity of a particle the age has let through so far, 0-1 (fade_in:)
|
||||||
|
float
|
||||||
|
fade_in( float const Age ) const {
|
||||||
|
if( m_fadein <= 0.f ) { return 1.f; }
|
||||||
|
auto const share { std::clamp( Age / m_fadein, 0.f, 1.f ) };
|
||||||
|
return share * share * ( 3.f - 2.f * share ); }
|
||||||
glm::vec3 const &
|
glm::vec3 const &
|
||||||
color() const {
|
color() const {
|
||||||
return m_emitter.color; }
|
return m_emitter.color; }
|
||||||
@@ -199,6 +207,11 @@ private:
|
|||||||
bool m_settles { false };
|
bool m_settles { false };
|
||||||
float m_settling { 0.f }; // terminal_velocity:
|
float m_settling { 0.f }; // terminal_velocity:
|
||||||
float m_drag { 1.f }; // drag:
|
float m_drag { 1.f }; // drag:
|
||||||
|
// optional growth of the particles with the way they go through the air, metres of size per metre: the jet out of the
|
||||||
|
// exhaust widens into a cone as it takes in the air around, instead of the puffs swelling in one place
|
||||||
|
float m_spread { 0.f }; // spread:
|
||||||
|
// optional time the particles take to show up after they're born, seconds, so they don't pop up at the exhaust
|
||||||
|
float m_fadein { 0.f }; // fade_in:
|
||||||
// texture_handle m_texture { -1 }; // texture assigned to particle billboards
|
// texture_handle m_texture { -1 }; // texture assigned to particle billboards
|
||||||
// current state
|
// current state
|
||||||
float m_spawncount { 0.f }; // number of particles to spawn during next update
|
float m_spawncount { 0.f }; // number of particles to spawn during next update
|
||||||
|
|||||||
@@ -19,10 +19,10 @@ struct smoke_source_s
|
|||||||
vec4 previous; // xyz: emitter at the update before, from the origin
|
vec4 previous; // xyz: emitter at the update before, from the origin
|
||||||
vec4 launch; // xy: inclination, radians, zw: speed, m/s
|
vec4 launch; // xy: inclination, radians, zw: speed, m/s
|
||||||
vec4 initial; // xy: size, zw: opacity
|
vec4 initial; // xy: size, zw: opacity
|
||||||
vec4 sizechange; // x: per second, y: min, z: max
|
vec4 sizechange; // x: per second, y: min, z: max, w: per metre the particle goes through the air (spread:)
|
||||||
vec4 opacitychange; // x: per second, y: min, z: max
|
vec4 opacitychange; // x: per second, y: min, z: max
|
||||||
vec4 motion; // x: rise, y: damping (per second, of the vertical velocity), z: least vertical velocity
|
vec4 motion; // x: rise, y: damping (per second, of the vertical velocity), z: least vertical velocity
|
||||||
vec4 settling; // x: velocity the particles settle at, m/s upwards, y: drag, per second, z: 1 when they settle (in place of motion)
|
vec4 settling; // x: velocity the particles settle at, m/s upwards, y: drag, per second, z: 1 when they settle (in place of motion), w: seconds they take to show up (fade_in:)
|
||||||
vec4 color; // rgb: colour of the smoke, lit by the lights of the pass
|
vec4 color; // rgb: colour of the smoke, lit by the lights of the pass
|
||||||
vec4 oldcolor; // rgb: colour lit as the cpu does it, without the lights (gfx.smoke.lighting off)
|
vec4 oldcolor; // rgb: colour lit as the cpu does it, without the lights (gfx.smoke.lighting off)
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -48,5 +48,9 @@ void main()
|
|||||||
vec3 color = source.oldcolor.rgb;
|
vec3 color = source.oldcolor.rgb;
|
||||||
if (options.x > 0.5)
|
if (options.x > 0.5)
|
||||||
color = source.color.rgb * particle_light((view * vec4(world, 1.0)).xyz, world, options.y);
|
color = source.color.rgb * particle_light((view * vec4(world, 1.0)).xyz, world, options.y);
|
||||||
particle_emit(world, size, vec3(particle.position.w, 0.0, 0.0), color, clamp(particle.state.x, 0.0, 1.0), uint(options.z));
|
float opacity = clamp(particle.state.x, 0.0, 1.0);
|
||||||
|
// showing up after the birth (smoke_source::fade_in())
|
||||||
|
if (source.settling.w > 0.0)
|
||||||
|
opacity *= smoothstep(0.0, source.settling.w, particle.state.y);
|
||||||
|
particle_emit(world, size, vec3(particle.position.w, 0.0, 0.0), color, opacity, uint(options.z));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ bool advance(inout smoke_particle_s particle, smoke_source_s source, float secon
|
|||||||
if (particle.state.x <= 0.0)
|
if (particle.state.x <= 0.0)
|
||||||
return false;
|
return false;
|
||||||
particle.velocity.w = clamp(particle.velocity.w + source.sizechange.x * seconds, source.sizechange.y, source.sizechange.z);
|
particle.velocity.w = clamp(particle.velocity.w + source.sizechange.x * seconds, source.sizechange.y, source.sizechange.z);
|
||||||
|
// the jet widens with the way it goes
|
||||||
|
if (source.sizechange.w > 0.0)
|
||||||
|
particle.velocity.w = min(particle.velocity.w + source.sizechange.w * length(particle.velocity.xyz) * seconds, source.sizechange.z);
|
||||||
if (source.settling.z > 0.5)
|
if (source.settling.z > 0.5)
|
||||||
{
|
{
|
||||||
// the drag of the air takes the particle towards the velocity it settles at
|
// the drag of the air takes the particle towards the velocity it settles at
|
||||||
|
|||||||
Reference in New Issue
Block a user