particle collison testing

This commit is contained in:
jacob 2026-01-06 07:03:11 -06:00
parent 65d34d49af
commit 87a624eaeb
3 changed files with 155 additions and 38 deletions

View File

@ -894,12 +894,17 @@ void V_TickForever(WaveLaneCtx *lane)
frame->draw_cursor = MulXformV2(frame->xf.ui_to_draw, frame->ui_cursor); frame->draw_cursor = MulXformV2(frame->xf.ui_to_draw, frame->ui_cursor);
frame->world_cursor = MulXformV2(frame->xf.ui_to_world, frame->ui_cursor); frame->world_cursor = MulXformV2(frame->xf.ui_to_world, frame->ui_cursor);
b32 show_editor_ui = TweakBool("Show editor UI", 0);
frame->world_selection_start = frame->world_cursor; frame->world_selection_start = frame->world_cursor;
if (frame->is_editing) if (frame->is_editing)
{ {
b32 m1_held = frame->held_buttons[Button_M1]; b32 m1_held = frame->held_buttons[Button_M1];
b32 m2_held = frame->held_buttons[Button_M2]; b32 m2_held = frame->held_buttons[Button_M2];
// frame->selection_mode = V_SelectionMode_Tile; if (show_editor_ui)
{
frame->selection_mode = V_SelectionMode_Tile;
}
if (m1_held) if (m1_held)
{ {
frame->is_selecting = 1; frame->is_selecting = 1;
@ -1073,7 +1078,7 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Build panels //- Build panels
if (TweakBool("Show editor UI", 0) && frame->is_editing) if (show_editor_ui && frame->is_editing)
{ {
Struct(PanelDfsNode) { PanelDfsNode *next; b32 visited; V_Panel *panel; UI_Checkpoint cp; }; Struct(PanelDfsNode) { PanelDfsNode *next; b32 visited; V_Panel *panel; UI_Checkpoint cp; };
PanelDfsNode *first_panel_dfs = PushStruct(frame->arena, PanelDfsNode); PanelDfsNode *first_panel_dfs = PushStruct(frame->arena, PanelDfsNode);
@ -2682,12 +2687,14 @@ void V_TickForever(WaveLaneCtx *lane)
emitter->pos = frame->world_cursor; emitter->pos = frame->world_cursor;
emitter->angle = AngleFromVec2(dir); emitter->angle = AngleFromVec2(dir);
emitter->count = 1000; emitter->count = 100;
emitter->speed = 10; emitter->speed = 10;
emitter->seed = RandU64FromState(&frame->rand); emitter->seed = RandU64FromState(&frame->rand);
emitter->speed_spread = 1; emitter->speed_spread = 1;
emitter->angle_spread = 1; // emitter->angle_spread = 1;
// emitter->angle_spread = 0.5;
emitter->angle_spread = Tau / 4;
} }
// Flatten emitters list // Flatten emitters list
@ -2736,7 +2743,6 @@ void V_TickForever(WaveLaneCtx *lane)
params.target_rw = draw_target_rw; params.target_rw = draw_target_rw;
params.xf = frame->xf; params.xf = frame->xf;
params.seed = RandU64FromState(&frame->rand); params.seed = RandU64FromState(&frame->rand);
params.noise = G_BasicNoiseTexture();
params.selection_mode = frame->selection_mode; params.selection_mode = frame->selection_mode;
params.equipped_tile = frame->equipped_tile; params.equipped_tile = frame->equipped_tile;
@ -2770,6 +2776,7 @@ void V_TickForever(WaveLaneCtx *lane)
// Constants // Constants
G_SetConstant(frame->cl, V_ShaderConst_State, gpu_state_ref); G_SetConstant(frame->cl, V_ShaderConst_State, gpu_state_ref);
G_SetConstant(frame->cl, V_ShaderConst_Params, gpu_params_ref); G_SetConstant(frame->cl, V_ShaderConst_Params, gpu_params_ref);
G_SetConstant(frame->cl, V_ShaderConst_NoiseTex, G_BasicNoiseTexture());
// Sync // Sync
G_DumbGlobalMemorySync(frame->cl); G_DumbGlobalMemorySync(frame->cl);
@ -2795,6 +2802,19 @@ void V_TickForever(WaveLaneCtx *lane)
G_DiscardRenderTarget(frame->cl, draw_target); G_DiscardRenderTarget(frame->cl, draw_target);
//////////////////////////////
//- 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));
}
////////////////////////////// //////////////////////////////
//- Backdrop pass //- Backdrop pass
@ -2820,19 +2840,6 @@ 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

View File

@ -144,6 +144,25 @@ ComputeShader2D(V_BackdropCS, 8, 8)
result = bounds_color; result = bounds_color;
} }
} }
// TODO: Remove this
// Decals test
{
RWTexture2D<V_ParticleKind> decals = G_Dereference<V_ParticleKind>(params.decals);
Vec2 decal_pos = mul(params.xf.world_to_decal, Vec3(world_pos, 1));
// Vec2 decal_uv = decal_pos / countof(decals);
V_ParticleKind decal = decals.Load(decal_pos);
if (decal == V_ParticleKind_Test)
{
result = Color_Yellow;
// result = LinearFromSrgb(Vec4(0.5, 0.1, 0.1, 1));
}
}
} }
target[SV_DispatchThreadID] = result; target[SV_DispatchThreadID] = result;
@ -235,6 +254,7 @@ ComputeShader(V_SimParticlesCS, 64)
V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0]; V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0];
RWStructuredBuffer<V_Particle> particles = G_Dereference<V_Particle>(params.particles); RWStructuredBuffer<V_Particle> particles = G_Dereference<V_Particle>(params.particles);
RWTexture2D<V_ParticleKind> decals = G_Dereference<V_ParticleKind>(params.decals); RWTexture2D<V_ParticleKind> decals = G_Dereference<V_ParticleKind>(params.decals);
Texture2D<S_TileKind> tiles = G_Dereference<S_TileKind>(params.tiles);
u32 particle_idx = SV_DispatchThreadID; u32 particle_idx = SV_DispatchThreadID;
if (particle_idx < params.max_particles) if (particle_idx < params.max_particles)
@ -247,17 +267,14 @@ 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];
// TODO: Faster mix
u64 seed = MixU64(emitter.seed + particle.idx_in_emitter); u64 seed = MixU64(emitter.seed + particle.idx_in_emitter);
// TODO: Blue noise
u32 speed_noise = ((u32)seed >> 0) & 0xFFFF; u32 speed_noise = ((u32)seed >> 0) & 0xFFFF;
u32 angle_noise = ((u32)seed >> 16) & 0xFFFF; u32 angle_noise = ((u32)seed >> 16) & 0xFFFF;
f32 speed_rand = speed_noise / (f32)0xFFFF; f32 speed_rand = speed_noise / (f32)0xFFFF;
f32 angle_rand = angle_noise / (f32)0xFFFF; f32 angle_rand = angle_noise / (f32)0xFFFF;
f32 speed = emitter.speed + ((speed_rand * 2 - 1) * emitter.speed_spread); f32 speed = emitter.speed + ((speed_rand - 0.5) * emitter.speed_spread);
f32 angle = emitter.angle + ((angle_rand * 2 - 1) * emitter.angle_spread); f32 angle = emitter.angle + ((angle_rand - 0.5) * emitter.angle_spread);
particle.pos = emitter.pos; particle.pos = emitter.pos;
particle.velocity = Vec2(cos(angle), sin(angle)) * speed; particle.velocity = Vec2(cos(angle), sin(angle)) * speed;
@ -268,7 +285,100 @@ ComputeShader(V_SimParticlesCS, 64)
// Simulate // Simulate
{ {
f32 dt = params.dt; f32 dt = params.dt;
particle.pos += particle.velocity * dt;
Vec2 pos_a = particle.pos;
Vec2 pos_b = pos_a + particle.velocity * dt;
// TODO: Don't query tiles
Vec2I32 tile_pos_a = S_TilePosFromWorldPos(pos_a);
S_TileKind tile_a = tiles.Load(Vec3I32(tile_pos_a, 0));
b32 is_blocked_a = tile_a == S_TileKind_Wall;
Vec2 pos_a_decal = mul(params.xf.world_to_decal, Vec3(pos_a, 1));
Vec2 pos_b_decal = mul(params.xf.world_to_decal, Vec3(pos_b, 1));
Vec2 step_a = pos_a_decal;
Vec2 step_b = pos_b_decal;
Vec2 step_vab = step_b - step_a;
f32 slope = step_vab.y / step_vab.x;
i32 x_dir = (step_vab.x >= 0) - (step_vab.x < 0);
if (!is_blocked_a)
{
i32 step_x = step_a.x;
for (;;)
{
f32 step_y = step_a.y + slope * (step_x - step_a.x);
Vec2 step = Vec2(step_x, step_y);
// TODO: Don't query tiles
Vec2 world_step = mul(params.xf.decal_to_world, Vec3(step, 1));
Vec2I32 tile_pos = S_TilePosFromWorldPos(world_step);
S_TileKind tile = tiles.Load(Vec3I32(tile_pos, 0));
b32 is_blocked = tile == S_TileKind_Wall;
if (is_blocked)
{
// particle.velocity *= -1;
particle.velocity.y *= -1;
// particle.velocity.x *= -1;
break;
}
step_x += x_dir;
if (x_dir > 0)
{
if (step_x > (step_b.x + x_dir))
{
break;
}
}
else
{
if (step_x < (step_b.x + x_dir))
{
break;
}
}
}
}
// // Line walk
// // FIXME: Real line walk, not aabb check
// b32 is_blocked = 0;
// for (u32 step_y = step_a.y; step_y <= step_b.y; ++step_y)
// {
// for (u32 step_x = step_a.x; step_x <= step_b.x; ++step_x)
// {
// // TODO: Don't query tiles
// Vec2 world_step = mul(params.xf.decal_to_world, Vec3(step_x, step_y, 1));
// Vec2I32 tile_pos = S_TilePosFromWorldPos(world_step);
// S_TileKind tile = tiles.Load(Vec3I32(tile_pos, 0));
// if (tile == S_TileKind_Wall)
// {
// if (is_blocked)
// {
// // particle.velocity *= -1;
// particle.velocity.x *= -1;
// break;
// }
// is_blocked = 1;
// }
// }
// }
// Vec2I32 tile_pos = S_TilePosFromWorldPos(pos_a);
// S_TileKind tile = tiles.Load(Vec3I32(tile_pos, 0));
particle.pos = pos_a + particle.velocity * dt;
particle.velocity = lerp(particle.velocity, 0, 4 * params.dt);
Vec2 decal_pos = mul(params.xf.world_to_decal, Vec3(particle.pos, 1)); Vec2 decal_pos = mul(params.xf.world_to_decal, Vec3(particle.pos, 1));
if (decal_pos.x >= 0 && decal_pos.y >= 0 && decal_pos.x < countof(decals).x && decal_pos.y < countof(decals).y) if (decal_pos.x >= 0 && decal_pos.y >= 0 && decal_pos.x < countof(decals).x && decal_pos.y < countof(decals).y)
@ -393,20 +503,20 @@ PixelShader(V_OverlayPS, V_OverlayPSOutput, V_OverlayPSInput input)
} }
} }
// TODO: Remove this // // TODO: Remove this
// Decals test // // Decals test
{ // {
RWTexture2D<V_ParticleKind> decals = G_Dereference<V_ParticleKind>(params.decals); // RWTexture2D<V_ParticleKind> decals = G_Dereference<V_ParticleKind>(params.decals);
Vec2 decal_pos = mul(params.xf.world_to_decal, Vec3(world_pos, 1)); // Vec2 decal_pos = mul(params.xf.world_to_decal, Vec3(world_pos, 1));
// Vec2 decal_uv = decal_pos / countof(decals); // // Vec2 decal_uv = decal_pos / countof(decals);
V_ParticleKind decal = decals.Load(floor(decal_pos)); // V_ParticleKind decal = decals.Load(decal_pos);
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)); // // result = LinearFromSrgb(Vec4(0.5, 0.1, 0.1, 1));
} // }
} // }
V_OverlayPSOutput output; V_OverlayPSOutput output;

View File

@ -6,6 +6,7 @@
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);
G_DeclConstant(G_Texture3DRef, V_ShaderConst_NoiseTex, 2);
Enum(V_SelectionMode) Enum(V_SelectionMode)
{ {
@ -48,7 +49,6 @@ Struct(V_GpuParams)
V_Xforms xf; V_Xforms xf;
u64 seed; u64 seed;
G_Texture3DRef noise;
V_SelectionMode selection_mode; V_SelectionMode selection_mode;
S_TileKind equipped_tile; S_TileKind equipped_tile;