17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-21 16:33:00 +02:00

Let the templates of smoke sources set how fast their particles rise or fall

This commit is contained in:
2026-10-20 17:12:23 +02:00
parent 867497b658
commit abbdca4773
7 changed files with 47 additions and 6 deletions

View File

@@ -269,6 +269,11 @@ are no longer loaded.
what it doesn't see and lights the rest with the sun (with the shadows of the terrain, models and clouds), the sky and
the lamps and headlights, as the surfaces are lit: smoke in the shade is darker, smoke against the sun glows, smoke in
the beam of headlights at night is lit by it.
- **Templates of smoke sources** (`data/smokesource_*.txt`, both renderers) may say how heavy the particles are: with
`terminal_velocity: v` (m/s, positive up: light, hot smoke rises; negative down: dust, sand, sparks fall) the velocity
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
cold and humid air); a template without it behaves as before. The particles don't stop at the ground.
- **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
drawn as a streak of its motion against the camera: they slant when the train moves. They are lit like the smoke, so the

View File

@@ -526,10 +526,11 @@ namespace gl
glm::vec4 sizechange;
glm::vec4 opacitychange;
glm::vec4 motion;
glm::vec4 settling;
glm::vec4 color;
glm::vec4 oldcolor;
};
static_assert(sizeof(particle_smoke_source) == 160, "bad size of particle_smoke_source");
static_assert(sizeof(particle_smoke_source) == 176, "bad size of particle_smoke_source");
// layout std430: GLSL particle_draw_s, read by the draws as attributes of instances
struct particle_draw

View File

@@ -249,6 +249,7 @@ void opengl46_gpu_particles::simulate_smoke(particle_manager &Particles, glm::dv
record.sizechange = glm::vec4{state.sizechange[0], state.sizechange[1], state.sizechange[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.settling = glm::vec4{state.settling, state.drag, state.settles ? 1.f : 0.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};
if (pool.size > 0)

View File

@@ -115,6 +115,13 @@ smoke_source::deserialize_mapping( cParser &Input ) {
else if( key == "opacity_change:" ) {
m_opacitymodifier.deserialize( Input );
}
else if( key == "terminal_velocity:" ) {
m_settles = true;
m_settling = Input.getToken<float>( true, "\n\r\t ,;[]" );
}
else if( key == "drag:" ) {
m_drag = 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
}
@@ -379,9 +386,14 @@ smoke_source::update( smoke_particle &Particle, bounding_box &Boundingbox, doubl
// ... otherwise proceed with full update
m_sizemodifier.update( Particle.size, Timedelta );
if( m_settles ) {
// the drag of the air takes the particle towards the velocity it settles at
auto const share { static_cast<float>( 1.0 - std::exp( -m_drag * Timedelta ) ) };
Particle.velocity += ( glm::vec3{ 0.f, m_settling, 0.f } - Particle.velocity ) * share;
}
// crude smoke dispersion simulation
// http://www.auburn.edu/academic/forestry_wildlife/fire/smoke_guide/smoke_dispersion.htm
if (m_ownertype == owner_type::vehicle)
else if (m_ownertype == owner_type::vehicle)
{
Particle.velocity.y += static_cast<float>(( 0.025 * Particle.velocity.y ) * std::min( 0.f, Global.AirTemperature - 90 ) * Timedelta); // decelerate faster in cold weather
Particle.velocity.y -= static_cast<float>(( (0.05 * (pow(m_owner.vehicle->GetVelocity()*1,0.4))) * Particle.velocity.y ) * Global.Overcast * Timedelta); // decelerate faster with high air humidity and/or precipitation
@@ -451,6 +463,9 @@ smoke_source::update_gpu( double const Timedelta, bool const Onlydespawn ) {
m_gpu.damping = static_cast<float>( 0.050 * Global.Overcast );
m_gpu.risemin = static_cast<float>( 0.25 * ( 2.f - Global.Overcast ) );
}
m_gpu.settles = m_settles;
m_gpu.settling = m_settling;
m_gpu.drag = m_drag;
m_gpu.color = m_emitter.color;
// the renderer culls the particles one by one; the area is where they come from, for the distance of the source

View File

@@ -101,6 +101,10 @@ public:
float rise { 0.f };
float damping { 0.f };
float risemin { std::numeric_limits<float>::lowest() };
// with a settling velocity (settles): the velocity goes over to it instead, see smoke_source::m_settling
bool settles { false };
float settling { 0.f };
float drag { 1.f };
glm::vec3 color { 0.f };
};
// methods
@@ -189,6 +193,12 @@ private:
fixedstep_modifier<float> m_sizemodifier; // particle billboard size
// fixedstep_modifier<glm::vec3> m_colormodifier; // particle billboard color and opacity
fixedstep_modifier<float> m_opacitymodifier;
// optional velocity the particles settle at in still air, m/s, positive upwards (light, hot smoke rises, heavy particles
// fall), and how fast they get to it: the share of the rest of the way per second is 1 - exp(-drag). when given, it takes
// the place of the crude dispersion of update( Particle ) (the rise in cold air, the damping in humid air)
bool m_settles { false };
float m_settling { 0.f }; // terminal_velocity:
float m_drag { 1.f }; // drag:
// texture_handle m_texture { -1 }; // texture assigned to particle billboards
// current state
float m_spawncount { 0.f }; // number of particles to spawn during next update

View File

@@ -22,6 +22,7 @@ struct smoke_source_s
vec4 sizechange; // 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 settling; // x: velocity the particles settle at, m/s upwards, y: drag, per second, z: 1 when they settle (in place of motion)
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)
};

View File

@@ -37,10 +37,18 @@ bool advance(inout smoke_particle_s particle, smoke_source_s source, float secon
if (particle.state.x <= 0.0)
return false;
particle.velocity.w = clamp(particle.velocity.w + source.sizechange.x * seconds, source.sizechange.y, source.sizechange.z);
// crude smoke dispersion
particle.velocity.y += source.motion.x * particle.velocity.y * seconds;
particle.velocity.y -= source.motion.y * particle.velocity.y * seconds;
particle.velocity.y = max(source.motion.z, particle.velocity.y);
if (source.settling.z > 0.5)
{
// the drag of the air takes the particle towards the velocity it settles at
particle.velocity.xyz += (vec3(0.0, source.settling.x, 0.0) - particle.velocity.xyz) * (1.0 - exp(-source.settling.y * seconds));
}
else
{
// crude smoke dispersion
particle.velocity.y += source.motion.x * particle.velocity.y * seconds;
particle.velocity.y -= source.motion.y * particle.velocity.y * seconds;
particle.velocity.y = max(source.motion.z, particle.velocity.y);
}
particle.position.xyz += particle.velocity.xyz * seconds;
particle.position.xyz += 0.1 * particle.state.y * wind.xyz * seconds;
particle.state.y += seconds;