track emitter particle sequence on cpu

This commit is contained in:
jacob 2026-01-07 01:22:20 -06:00
parent f30ed79e91
commit d0e119c476
4 changed files with 46 additions and 25 deletions

View File

@ -2633,25 +2633,37 @@ void V_TickForever(WaveLaneCtx *lane)
frame->emitters_count += 1; frame->emitters_count += 1;
emitter = &en->emitter; emitter = &en->emitter;
} }
V_ParticleFlag flags = V_ParticleFlag_StainOnPrune; V_ParticleFlag flags = 0;
flags |= V_ParticleFlag_StainOnPrune;
if (TweakBool("Emitter stain trail", 0))
{
flags |= V_ParticleFlag_StainTrail;
}
emitter->flags = flags; emitter->flags = flags;
Vec2 dir = victim_raycast.normal; Vec2 dir = victim_raycast.normal;
emitter->pos = victim_raycast.p; emitter->pos = victim_raycast.p;
emitter->count = 50; f32 count = TweakFloat("Emitter count", 50, 0, 10000);
f32 speed = TweakFloat("Emitter speed", 10, 0, 100);
f32 falloff = TweakFloat("Emitter falloff", 30, 0, 100);
// f32 angle_spread = TweakFloat("Emitter spread", Tau / 20, 0, Tau);
f32 angle_spread = TweakFloat("Emitter spread", 0.1, 0, 1) * Tau;
emitter->count = count;
// emitter->count = 100; // emitter->count = 100;
// emitter->count = 500; // emitter->count = 500;
emitter->speed = 10; emitter->speed = speed;
emitter->speed_spread = 20; emitter->speed_spread = speed * 2;
emitter->velocity_falloff = 30; emitter->velocity_falloff = falloff;
emitter->velocity_falloff_spread = 60; emitter->velocity_falloff_spread = falloff * 2;
emitter->angle = AngleFromVec2(dir); emitter->angle = AngleFromVec2(dir);
// emitter->angle_spread = Tau / 4; // emitter->angle_spread = Tau / 4;
emitter->angle_spread = Tau / 20; emitter->angle_spread = angle_spread;
// emitter->angle_spread = Tau / 32; // emitter->angle_spread = Tau / 32;
emitter->color_lin = LinearFromSrgb(VEC4(0.5, 0.1, 0.1, 1)); emitter->color_lin = LinearFromSrgb(VEC4(0.5, 0.1, 0.1, 1));
@ -2666,6 +2678,9 @@ void V_TickForever(WaveLaneCtx *lane)
// V_DrawPoint(victim_raycast.p, Color_Green); // V_DrawPoint(victim_raycast.p, Color_Green);
// V_DrawLine(victim_raycast.p, AddVec2(victim_raycast.p, MulVec2(victim_raycast.normal, 0.5)), Color_White); // V_DrawLine(victim_raycast.p, AddVec2(victim_raycast.p, MulVec2(victim_raycast.normal, 0.5)), Color_White);
emitter->first_particle_seq = V.particle_seq;
V.particle_seq += emitter->count;
} }
@ -2778,7 +2793,8 @@ void V_TickForever(WaveLaneCtx *lane)
case S_DebugDrawKind_Shape: case S_DebugDrawKind_Shape:
{ {
S_Shape ui_shape = S_MulXformShape(frame->xf.world_to_ui, desc->shape); S_Shape ui_shape = S_MulXformShape(frame->xf.world_to_ui, desc->shape);
V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line); // V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line);
V_DrawShape(ui_shape, color, detail, V_DrawFlag_None);
} break; } break;
} }
} }
@ -2814,6 +2830,9 @@ void V_TickForever(WaveLaneCtx *lane)
// emitter->angle_spread = 0.5; // emitter->angle_spread = 0.5;
emitter->angle_spread = Tau / 4; emitter->angle_spread = Tau / 4;
// emitter->angle_spread = Tau; // emitter->angle_spread = Tau;
emitter->first_particle_seq = V.particle_seq;
V.particle_seq += emitter->count;
} }
////////////////////////////// //////////////////////////////

View File

@ -289,6 +289,9 @@ Struct(V_Ctx)
V_Panel *root_panel; V_Panel *root_panel;
V_Window *dragging_window; V_Window *dragging_window;
// Atomic monotonically increasing allocation counter sequence for GPU particle ring buffer
u32 particle_seq;
Atomic32 shutdown; Atomic32 shutdown;
Fence shutdown_complete; Fence shutdown_complete;

View File

@ -259,18 +259,13 @@ ComputeShader(V_EmitParticlesCS, 64)
{ {
V_Emitter emitter = emitters[emitter_idx]; V_Emitter emitter = emitters[emitter_idx];
u32 first_particle_seq; for (u32 i = 0; i < emitter.count; ++i)
InterlockedAdd(state_buff[0].particle_seq, emitter.count, first_particle_seq);
u32 last_particle_seq = first_particle_seq + emitter.count;
u32 particles_created_count = 0;
for (u32 particle_seq = first_particle_seq; particle_seq < last_particle_seq; ++particle_seq)
{ {
u32 particle_seq = emitter.first_particle_seq + i;
u32 particle_idx = particle_seq % params.max_particles; u32 particle_idx = particle_seq % params.max_particles;
particles[particle_idx].exists = 1; particles[particle_idx].exists = 1;
particles[particle_idx].emitter_init_num = emitter_idx + 1; particles[particle_idx].emitter_init_num = emitter_idx + 1;
particles[particle_idx].idx_in_emitter = particles_created_count; particles[particle_idx].seq = particle_seq;
particles_created_count += 1;
} }
} }
} }
@ -296,7 +291,7 @@ ComputeShader(V_SimParticlesCS, 64)
{ {
V_Emitter emitter = G_Dereference<V_Emitter>(params.emitters)[particle.emitter_init_num - 1]; V_Emitter emitter = G_Dereference<V_Emitter>(params.emitters)[particle.emitter_init_num - 1];
u64 seed = MixU64(emitter.seed + particle.idx_in_emitter); u64 seed = MixU64(emitter.seed + particle.seq);
// u32 speed_noise = (u32)((seed >> 0) & 0xFF); // u32 speed_noise = (u32)((seed >> 0) & 0xFF);
// u32 angle_noise = (u32)((seed >> 8) & 0xFF); // u32 angle_noise = (u32)((seed >> 8) & 0xFF);
@ -321,6 +316,7 @@ ComputeShader(V_SimParticlesCS, 64)
f32 velocity_falloff = emitter.velocity_falloff + rand_falloff * emitter.velocity_falloff; f32 velocity_falloff = emitter.velocity_falloff + rand_falloff * emitter.velocity_falloff;
Vec3 color = emitter.color_lin.rgb + Vec3(rand_r, rand_g, rand_b) * emitter.color_spread; Vec3 color = emitter.color_lin.rgb + Vec3(rand_r, rand_g, rand_b) * emitter.color_spread;
particle.flags = emitter.flags;
particle.pos = emitter.pos; particle.pos = emitter.pos;
particle.velocity = Vec2(cos(angle), sin(angle)) * speed; particle.velocity = Vec2(cos(angle), sin(angle)) * speed;
particle.velocity_falloff = velocity_falloff; particle.velocity_falloff = velocity_falloff;
@ -333,7 +329,7 @@ ComputeShader(V_SimParticlesCS, 64)
{ {
particle.pos += particle.velocity * params.dt; particle.pos += particle.velocity * params.dt;
particle.velocity = lerp(particle.velocity, 0, particle.velocity_falloff * params.dt); particle.velocity = lerp(particle.velocity, 0, particle.velocity_falloff * params.dt);
if (particle.exists < 0.0001) if (particle.exists < 0.001 || dot(particle.velocity, particle.velocity) < (0.001 * 0.001))
{ {
particle.exists = 0; particle.exists = 0;
} }
@ -346,7 +342,7 @@ ComputeShader(V_SimParticlesCS, 64)
if (cell_pos.x >= 0 && cell_pos.y >= 0 && cell_pos.x < countof(stains).x && cell_pos.y < countof(stains).y) if (cell_pos.x >= 0 && cell_pos.y >= 0 && cell_pos.x < countof(stains).x && cell_pos.y < countof(stains).y)
{ {
b32 should_stain = 0; b32 should_stain = 0;
if (particle.flags & V_ParticleFlag_StainOnPrune && particle.exists == 0) if (particle.flags & V_ParticleFlag_StainTrail || ((particle.flags & V_ParticleFlag_StainOnPrune) && particle.exists == 0))
{ {
should_stain = 1; should_stain = 1;
} }

View File

@ -35,7 +35,8 @@ Struct(V_Xforms)
Struct(V_GpuState) Struct(V_GpuState)
{ {
u32 particle_seq; // Atomic monotonically increasing allocation counter sequence for particle ring buffer // u32 particle_seq; // Atomic monotonically increasing allocation counter sequence for particle ring buffer
i32 _;
}; };
Struct(V_GpuParams) Struct(V_GpuParams)
@ -87,16 +88,19 @@ Enum(V_ParticleFlag)
{ {
V_ParticleFlag_None = 0, V_ParticleFlag_None = 0,
V_ParticleFlag_StainOnPrune = (1 << 0), V_ParticleFlag_StainOnPrune = (1 << 0),
V_ParticleFlag_StainTrail = (1 << 1),
}; };
Struct(V_Emitter) Struct(V_Emitter)
{ {
V_ParticleFlag flags; V_ParticleFlag flags;
Vec2 pos; u32 first_particle_seq;
u32 count; u32 count;
u64 seed; u64 seed;
Vec2 pos;
f32 speed; f32 speed;
f32 speed_spread; f32 speed_spread;
@ -113,11 +117,10 @@ Struct(V_Emitter)
// TODO: Pack this efficiently // TODO: Pack this efficiently
Struct(V_Particle) Struct(V_Particle)
{ {
V_ParticleFlag flags; u32 emitter_init_num; // if != 0, then initialize using emitter at index [emitter_init_num - 1]
u32 emitter_init_num; // if != 0, then initialize using emitter at index (emitter_init_num - 1)
u32 seq; u32 seq;
u32 idx_in_emitter;
V_ParticleFlag flags;
Vec2 pos; Vec2 pos;
Vec2 velocity; Vec2 velocity;