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;
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;
Vec2 dir = victim_raycast.normal;
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 = 500;
emitter->speed = 10;
emitter->speed_spread = 20;
emitter->speed = speed;
emitter->speed_spread = speed * 2;
emitter->velocity_falloff = 30;
emitter->velocity_falloff_spread = 60;
emitter->velocity_falloff = falloff;
emitter->velocity_falloff_spread = falloff * 2;
emitter->angle = AngleFromVec2(dir);
// emitter->angle_spread = Tau / 4;
emitter->angle_spread = Tau / 20;
emitter->angle_spread = angle_spread;
// emitter->angle_spread = Tau / 32;
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_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:
{
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;
}
}
@ -2814,6 +2830,9 @@ void V_TickForever(WaveLaneCtx *lane)
// emitter->angle_spread = 0.5;
emitter->angle_spread = Tau / 4;
// 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_Window *dragging_window;
// Atomic monotonically increasing allocation counter sequence for GPU particle ring buffer
u32 particle_seq;
Atomic32 shutdown;
Fence shutdown_complete;

View File

@ -259,18 +259,13 @@ ComputeShader(V_EmitParticlesCS, 64)
{
V_Emitter emitter = emitters[emitter_idx];
u32 first_particle_seq;
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)
for (u32 i = 0; i < emitter.count; ++i)
{
u32 particle_seq = emitter.first_particle_seq + i;
u32 particle_idx = particle_seq % params.max_particles;
particles[particle_idx].exists = 1;
particles[particle_idx].emitter_init_num = emitter_idx + 1;
particles[particle_idx].idx_in_emitter = particles_created_count;
particles_created_count += 1;
particles[particle_idx].seq = particle_seq;
}
}
}
@ -296,7 +291,7 @@ ComputeShader(V_SimParticlesCS, 64)
{
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 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;
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.velocity = Vec2(cos(angle), sin(angle)) * speed;
particle.velocity_falloff = velocity_falloff;
@ -333,7 +329,7 @@ ComputeShader(V_SimParticlesCS, 64)
{
particle.pos += particle.velocity * 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;
}
@ -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)
{
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;
}

View File

@ -35,7 +35,8 @@ Struct(V_Xforms)
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)
@ -87,16 +88,19 @@ Enum(V_ParticleFlag)
{
V_ParticleFlag_None = 0,
V_ParticleFlag_StainOnPrune = (1 << 0),
V_ParticleFlag_StainTrail = (1 << 1),
};
Struct(V_Emitter)
{
V_ParticleFlag flags;
Vec2 pos;
u32 first_particle_seq;
u32 count;
u64 seed;
Vec2 pos;
f32 speed;
f32 speed_spread;
@ -113,11 +117,10 @@ Struct(V_Emitter)
// TODO: Pack this efficiently
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 idx_in_emitter;
V_ParticleFlag flags;
Vec2 pos;
Vec2 velocity;