more particle testing

This commit is contained in:
jacob 2026-01-06 03:29:22 -06:00
parent b8e08c72ad
commit 65d34d49af
8 changed files with 103 additions and 73 deletions

Binary file not shown.

Binary file not shown.

View File

@ -15,6 +15,8 @@
@EmbedDir V_Resources pp_vis_res @EmbedDir V_Resources pp_vis_res
@ComputeShader V_ClearDecalsCS
@ComputeShader V_ClearParticlesCS
@ComputeShader V_BackdropCS @ComputeShader V_BackdropCS
@VertexShader V_DQuadVS @VertexShader V_DQuadVS
@PixelShader V_DQuadPS @PixelShader V_DQuadPS

View File

@ -311,7 +311,8 @@ void V_TickForever(WaveLaneCtx *lane)
Vec2I32 tiles_dims = VEC2I32(S_TilesPitch, S_TilesPitch); Vec2I32 tiles_dims = VEC2I32(S_TilesPitch, S_TilesPitch);
Vec2I32 decals_dims = VEC2I32(V_PixelsPerMeter * S_WorldPitch, V_PixelsPerMeter * S_WorldPitch); Vec2I32 decals_dims = VEC2I32(V_PixelsPerMeter * S_WorldPitch, V_PixelsPerMeter * S_WorldPitch);
u32 max_particles = Kibi(128); // u32 max_particles = Kibi(128);
u32 max_particles = Mebi(1);
// Init gpu state // Init gpu state
G_ResourceHandle gpu_state = Zi; G_ResourceHandle gpu_state = Zi;
@ -2350,6 +2351,8 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Process vis commands //- Process vis commands
b32 should_clear_decals = !TweakBool("Persist decals", 0);
b32 should_clear_particles = 0;
for (V_CmdNode *cmd_node = frame->first_cmd_node; cmd_node; cmd_node = cmd_node->next) for (V_CmdNode *cmd_node = frame->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
{ {
String cmd_name = cmd_node->cmd.name; String cmd_name = cmd_node->cmd.name;
@ -2486,6 +2489,16 @@ void V_TickForever(WaveLaneCtx *lane)
ent->exists = 0; ent->exists = 0;
} }
} break; } break;
case V_CmdKind_clear_decals:
{
should_clear_decals = 1;
} break;
case V_CmdKind_clear_particles:
{
should_clear_particles = 1;
} break;
} }
} }
@ -2652,7 +2665,9 @@ void V_TickForever(WaveLaneCtx *lane)
V_EmitterNode *first_emitter_node = 0; V_EmitterNode *first_emitter_node = 0;
V_EmitterNode *last_emitter_node = 0; V_EmitterNode *last_emitter_node = 0;
// Spawn test emitters // Spawn test emitter
if (frame->held_buttons[Button_F])
{ {
V_Emitter *emitter = 0; V_Emitter *emitter = 0;
{ {
@ -2663,16 +2678,16 @@ void V_TickForever(WaveLaneCtx *lane)
} }
emitter->particle_kind = V_ParticleKind_Test; emitter->particle_kind = V_ParticleKind_Test;
Vec2 dir = VEC2(0, 1); Vec2 dir = frame->look;
emitter->pos = frame->world_cursor; emitter->pos = frame->world_cursor;
emitter->angle = AngleFromVec2(dir); emitter->angle = AngleFromVec2(dir);
emitter->count = 1000; emitter->count = 1000;
emitter->speed = 4; emitter->speed = 10;
emitter->seed = RandU64FromState(&frame->rand); emitter->seed = RandU64FromState(&frame->rand);
emitter->speed_spread = 1; emitter->speed_spread = 1;
emitter->angle_spread = Tau; emitter->angle_spread = 1;
} }
// Flatten emitters list // Flatten emitters list
@ -2759,6 +2774,22 @@ void V_TickForever(WaveLaneCtx *lane)
// Sync // Sync
G_DumbGlobalMemorySync(frame->cl); G_DumbGlobalMemorySync(frame->cl);
//////////////////////////////
//- Utility pass
// Clear decals
if (should_clear_decals)
{
G_Compute(frame->cl, V_ClearDecalsCS, V_ThreadGroupSizeFromTexSize(decals_dims));
}
// Clear particles
if (should_clear_particles)
{
G_Compute(frame->cl, V_ClearParticlesCS, V_ThreadGroupSizeFromBufferSize(max_particles));
}
G_DumbGlobalMemorySync(frame->cl);
////////////////////////////// //////////////////////////////
//- Discard pass //- Discard pass
@ -2770,7 +2801,7 @@ void V_TickForever(WaveLaneCtx *lane)
G_DumbMemoryLayoutSync(frame->cl, draw_target, G_Layout_DirectQueue_ShaderReadWrite); G_DumbMemoryLayoutSync(frame->cl, draw_target, G_Layout_DirectQueue_ShaderReadWrite);
{ {
G_Compute(frame->cl, V_BackdropCS, V_BackdropCSThreadSizeFromTexSize(frame->draw_dims)); G_Compute(frame->cl, V_BackdropCS, V_ThreadGroupSizeFromTexSize(frame->draw_dims));
} }
////////////////////////////// //////////////////////////////
@ -2789,6 +2820,19 @@ void V_TickForever(WaveLaneCtx *lane)
); );
} }
//////////////////////////////
//- Particle simulation pass
{
// Emit particles
G_Compute(frame->cl, V_EmitParticlesCS, V_ThreadGroupSizeFromBufferSize(emitters_count));
G_DumbMemorySync(frame->cl, gpu_particles);
// Simulate particles
G_Compute(frame->cl, V_SimParticlesCS, V_ThreadGroupSizeFromBufferSize(max_particles));
}
////////////////////////////// //////////////////////////////
//- Overlay pass //- Overlay pass
@ -2803,19 +2847,6 @@ void V_TickForever(WaveLaneCtx *lane)
); );
} }
//////////////////////////////
//- Particle simulation pass
{
// Emit particles
G_Compute(frame->cl, V_EmitParticlesCS, VEC3I32((emitters_count + 63) / 64, 1, 1));
G_DumbMemorySync(frame->cl, gpu_particles);
// Simulate particles
G_Compute(frame->cl, V_SimParticlesCS, VEC3I32((max_particles + 63) / 64, 1, 1));
}
////////////////////////////// //////////////////////////////
//- Finalize draw target //- Finalize draw target

View File

@ -15,6 +15,8 @@
X(spawn, Spawn/Teleport Player, V_CmdDescFlag_None, V_HOTKEY( Button_T ), ) \ X(spawn, Spawn/Teleport Player, V_CmdDescFlag_None, V_HOTKEY( Button_T ), ) \
X(spawn_dummy, Spawn Dummy, V_CmdDescFlag_None, V_HOTKEY( Button_R ), ) \ X(spawn_dummy, Spawn Dummy, V_CmdDescFlag_None, V_HOTKEY( Button_R ), ) \
X(delete, Delete entity at cursor, V_CmdDescFlag_None, V_HOTKEY( Button_M2 ), ) \ X(delete, Delete entity at cursor, V_CmdDescFlag_None, V_HOTKEY( Button_M2 ), ) \
X(clear_decals, Clear decals, V_CmdDescFlag_None, V_HOTKEY( Button_C ), ) \
X(clear_particles, Clear particles, V_CmdDescFlag_None, V_HOTKEY( Button_C, .alt = 1 ), ) \
/* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -1,3 +1,31 @@
////////////////////////////////////////////////////////////
//~ Utility shaders
//- Clear decals
ComputeShader2D(V_ClearDecalsCS, 8, 8)
{
V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0];
RWTexture2D<V_ParticleKind> decals = G_Dereference<V_ParticleKind>(params.decals);
Vec2 decal_idx = SV_DispatchThreadID;
if (decal_idx.x < countof(decals).x && decal_idx.y < countof(decals).y)
{
decals[decal_idx] = V_ParticleKind_None;
}
}
//- Clear particles
ComputeShader(V_ClearParticlesCS, 64)
{
V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0];
RWStructuredBuffer<V_Particle> particles = G_Dereference<V_Particle>(params.particles);
u32 particle_idx = SV_DispatchThreadID;
if (particle_idx < params.max_particles)
{
particles[particle_idx].kind = V_ParticleKind_None;
}
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Backdrop shader //~ Backdrop shader
@ -197,53 +225,6 @@ ComputeShader(V_EmitParticlesCS, 64)
particles_created_count += 1; particles_created_count += 1;
} }
} }
// V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0];
// RWStructuredBuffer<V_GpuState> state_buff = G_Dereference<V_GpuState>(V_ShaderConst_State);
// StructuredBuffer<V_Emitter> emitters = G_Dereference<V_Emitter>(params.emitters);
// RWStructuredBuffer<V_Particle> particles = G_Dereference<V_Particle>(params.particles);
// Texture3D<u32> noise3d = G_Dereference<u32>(params.noise);
// u32 emitter_idx = SV_DispatchThreadID;
// if (emitter_idx < params.emitters_count)
// {
// 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;
// Vec2U32 speed_noise_coord;
// Vec2U32 angle_noise_coord;
// {
// speed_noise_coord.x = ((emitter.speed_seed >> 0) & 0xFFFF) % countof(noise3d).x;
// speed_noise_coord.y = ((emitter.speed_seed >> 16) & 0xFFFF) % countof(noise3d).y;
// angle_noise_coord.x = ((emitter.angle_seed >> 0) & 0xFFFF) % countof(noise3d).x;
// angle_noise_coord.y = ((emitter.angle_seed >> 16) & 0xFFFF) % countof(noise3d).y;
// }
// u64 base_seed =
// for (u32 particle_seq = first_particle_seq; particle_seq < last_particle_seq; ++particle_seq)
// {
// V_Particle particle;
// {
// u32 speed_noise = noise3d.Load(Vec4U32(speed_noise_coord.xy, particle_seq % countof(noise3d).z, 0));
// u32 angle_noise = noise3d.Load(Vec4U32(angle_noise_coord.xy, particle_seq % countof(noise3d).z, 0));
// f32 speed_rand = speed_noise / (f32)0xFFFF;
// f32 angle_rand = angle_noise / (f32)0xFFFF;
// f32 speed = emitter.speed + ((speed_rand * 2 - 1) * emitter.speed_spread);
// f32 angle = emitter.angle + ((angle_rand * 2 - 1) * emitter.angle_spread);
// particle.kind = emitter.particle_kind;
// particle.pos = emitter.pos;
// particle.velocity = Vec2(cos(angle), sin(angle)) * speed;
// }
// particles[particle_seq % params.max_particles] = particle;
// }
// }
} }
////////////////////////////// //////////////////////////////
@ -295,6 +276,11 @@ ComputeShader(V_SimParticlesCS, 64)
// FIXME: Atomic write // FIXME: Atomic write
decals[floor(decal_pos)] = particle.kind; decals[floor(decal_pos)] = particle.kind;
} }
else
{
// Prune out of bounds particle
particle.kind = V_ParticleKind_None;
}
} }
particles[particle_idx] = particle; particles[particle_idx] = particle;
} }
@ -418,6 +404,7 @@ PixelShader(V_OverlayPS, V_OverlayPSOutput, V_OverlayPSInput input)
if (decal == V_ParticleKind_Test) if (decal == V_ParticleKind_Test)
{ {
result = Color_Yellow; result = Color_Yellow;
// result = LinearFromSrgb(Vec4(0.5, 0.1, 0.1, 1));
} }
} }

View File

@ -43,6 +43,10 @@ Struct(V_OverlayPSOutput)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Shaders //~ Shaders
//- Utility shaders
ComputeShader2D(V_ClearDecalsCS, 8, 8);
ComputeShader(V_ClearParticlesCS, 64);
//- Backdrop shader //- Backdrop shader
ComputeShader2D(V_BackdropCS, 8, 8); ComputeShader2D(V_BackdropCS, 8, 8);

View File

@ -4,8 +4,8 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Constant types //~ Constant types
G_DeclConstant(G_RWStructuredBufferRef, V_ShaderConst_State, 0); G_DeclConstant(G_RWStructuredBufferRef, V_ShaderConst_State, 0);
G_DeclConstant(G_StructuredBufferRef, V_ShaderConst_Params, 1); G_DeclConstant(G_StructuredBufferRef, V_ShaderConst_Params, 1);
Enum(V_SelectionMode) Enum(V_SelectionMode)
{ {
@ -39,7 +39,9 @@ Struct(V_GpuState)
Struct(V_GpuParams) Struct(V_GpuParams)
{ {
// TODO: Use simulation dt
f32 dt; f32 dt;
Vec2 target_size; Vec2 target_size;
G_Texture2DRef target_ro; G_Texture2DRef target_ro;
G_RWTexture2DRef target_rw; G_RWTexture2DRef target_rw;
@ -117,11 +119,6 @@ Struct(V_Particle)
}; };
#endif #endif
////////////////////////////////////////////////////////////
//~ Backdrop shader types
#define V_BackdropCSThreadSizeFromTexSize(tex_size) VEC3I32((tex_size.x + 7) / 8, (tex_size.y + 7) / 8, 1)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Quad types //~ Quad types
@ -144,3 +141,10 @@ Struct(V_DVert)
Vec2 pos; Vec2 pos;
Vec4 color_lin; Vec4 color_lin;
}; };
////////////////////////////////////////////////////////////
//~ Helpers
#define V_ThreadGroupSizeFromBufferSize(buffer_size) VEC3I32((((buffer_size) + 63) / 64), 1, 1)
#define V_ThreadGroupSizeFromTexSize(tex_size) VEC3I32(((tex_size).x + 7) / 8, ((tex_size).y + 7) / 8, 1)