From 463e142727fec113a32de885c3972649feea12f1 Mon Sep 17 00:00:00 2001 From: jacob Date: Fri, 13 Feb 2026 23:33:49 -0600 Subject: [PATCH] smoke particle testing --- src/base/base_math.c | 2 +- src/base/base_math.h | 2 +- src/base/base_shader.gh | 25 +++- src/meta/meta.c | 5 +- src/pp/pp_transcode.c | 2 +- src/pp/pp_vis/pp_vis_core.c | 207 ++++++++++++++++++++------------ src/pp/pp_vis/pp_vis_gpu.g | 194 +++++++++++++++++++++--------- src/pp/pp_vis/pp_vis_shared.cgh | 18 ++- 8 files changed, 313 insertions(+), 142 deletions(-) diff --git a/src/base/base_math.c b/src/base/base_math.c index cca11bf3..56622f77 100644 --- a/src/base/base_math.c +++ b/src/base/base_math.c @@ -551,7 +551,7 @@ Vec2 CeilVec2(Vec2 a) return VEC2(CeilF32(a.x), CeilF32(a.y)); } -//- Angle +//- Rotation // Returns 1 if winding between vectors a & b is clockwise or straight, -1 if counter-clockwise i32 WindingFromVec2(Vec2 a, Vec2 b) diff --git a/src/base/base_math.h b/src/base/base_math.h index 3840534b..e16cb966 100644 --- a/src/base/base_math.h +++ b/src/base/base_math.h @@ -384,7 +384,7 @@ Vec2 RoundVec2(Vec2 a); Vec2 FloorVec2(Vec2 a); Vec2 CeilVec2(Vec2 a); -//- Angle +//- Rotation i32 WindingFromVec2(Vec2 a, Vec2 b); Vec2 RotateVec2Angle(Vec2 v, f32 a); Vec2 RotateVec2(Vec2 a, Vec2 b); diff --git a/src/base/base_shader.gh b/src/base/base_shader.gh index d7eec125..b9128262 100644 --- a/src/base/base_shader.gh +++ b/src/base/base_shader.gh @@ -138,12 +138,33 @@ Inline f64 Norm53(u64 v) #define MatchFloor(a, b) all(floor(a) == floor(b)) //////////////////////////////////////////////////////////// -//~ Derivative helpers +//~ Rotation + +Inline Vec2 RotateVec2Angle(Vec2 v, f32 a) +{ + f32 c = cos(a); + f32 s = sin(a); + return Vec2(v.x * c - v.y * s, v.x * s + v.y * c); +} + +Inline Vec2 RotateVec2(Vec2 a, Vec2 b) +{ + return Vec2(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x); +} + +Inline Vec2 InvertRot(Vec2 r) +{ + r.y = -r.y; + return r; +} + +//////////////////////////////////////////////////////////// +//~ Derivatives #define fwidth_fine(v) (abs(ddx_fine((v))) + abs(ddy_fine((v)))) //////////////////////////////////////////////////////////// -//~ Color helpers +//~ Colors Inline Vec4 Vec4FromU32(u32 v) { diff --git a/src/meta/meta.c b/src/meta/meta.c index 1a411031..2cfd69df 100644 --- a/src/meta/meta.c +++ b/src/meta/meta.c @@ -533,9 +533,11 @@ void M_BuildEntryPoint(WaveLaneCtx *lane) //- Dxc { PushStringToList(perm, &cp.flags_dxc, Lit("-O3")); - PushStringToList(perm, &cp.flags_dxc, Lit("-Zi -Qembed_debug")); PushStringToList(perm, &cp.flags_dxc, Lit("-HV 202x")); // 202x makes numeric literals less weird + // TODO: Export debug info separately for release builds + PushStringToList(perm, &cp.flags_dxc, Lit("-Zi -Qembed_debug")); + // Enable warnings PushStringToList(perm, &cp.warnings_dxc, Lit("-Wall")); PushStringToList(perm, &cp.warnings_dxc, Lit("-Werror")); @@ -544,6 +546,7 @@ void M_BuildEntryPoint(WaveLaneCtx *lane) // Disable warnings PushStringToList(perm, &cp.warnings_dxc, Lit("-Wno-unused-variable")); PushStringToList(perm, &cp.warnings_dxc, Lit("-Wno-conversion")); + PushStringToList(perm, &cp.warnings_dxc, Lit("-Wno-switch")); } } diff --git a/src/pp/pp_transcode.c b/src/pp/pp_transcode.c index 7995dfd4..3b88c8d5 100644 --- a/src/pp/pp_transcode.c +++ b/src/pp/pp_transcode.c @@ -49,7 +49,7 @@ String P_PackWorld(Arena *arena, P_World *src_world) } if (ent->is_weapon) { - result.len += PushString(arena, Lit(" is_weapon\n")).len; + result.len += PushString(arena, Lit(" weapon\n")).len; } if (ent->is_bullet) { diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 834c8016..9f5114fc 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -392,17 +392,21 @@ void V_TickForever(WaveLaneCtx *lane) // Init gpu state G_ResourceHandle gpu_tiles_res = Zi; G_ResourceHandle gpu_particles_res = Zi; - G_ResourceHandle gpu_cells_res = Zi; G_ResourceHandle gpu_stains_res = Zi; + G_ResourceHandle gpu_ground_cells_res = Zi; + G_ResourceHandle gpu_air_cells_res = Zi; + G_ResourceHandle gpu_ground_densities_res = Zi; + G_ResourceHandle gpu_air_densities_res = Zi; G_ResourceHandle gpu_drynesses_res = Zi; - G_ResourceHandle gpu_densities_res = Zi; G_Texture2DRef gpu_tiles = Zi; G_RWStructuredBufferRef gpu_particles = Zi; - G_RWTexture2DRef gpu_cells = Zi; G_RWTexture2DRef gpu_stains = Zi; + G_RWTexture2DRef gpu_ground_cells = Zi; + G_RWTexture2DRef gpu_air_cells = Zi; + G_RWTexture2DRef gpu_ground_densities = Zi; + G_RWTexture2DRef gpu_air_densities = Zi; G_RWTexture2DRef gpu_drynesses = Zi; - G_RWTexture2DRef gpu_densities = Zi; { G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct); { @@ -429,29 +433,10 @@ void V_TickForever(WaveLaneCtx *lane) ); gpu_particles = G_PushRWStructuredBufferRef(gpu_perm, gpu_particles_res, V_Particle); } - // Init cells texture - { - gpu_cells_res = G_PushTexture2D( - gpu_perm, cl, - // G_Format_R8_Uint, - G_Format_R32_Uint, - // G_Format_R11G11B10_Float, - // G_Format_R10G10B10A2_Unorm, - // G_Format_R16G16B16A16_Float, - cells_dims, - G_Layout_DirectQueue_ShaderReadWrite, - .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite, - .name = Lit("Cells") - ); - gpu_cells = G_PushRWTexture2DRef(gpu_perm, gpu_cells_res); - } - // Init stain texture + // Init stains texture { gpu_stains_res = G_PushTexture2D( gpu_perm, cl, - // G_Format_R8_Uint, - // G_Format_R11G11B10_Float, - // G_Format_R10G10B10A2_Unorm, G_Format_R16G16B16A16_Float, cells_dims, G_Layout_DirectQueue_ShaderReadWrite, @@ -460,14 +445,58 @@ void V_TickForever(WaveLaneCtx *lane) ); gpu_stains = G_PushRWTexture2DRef(gpu_perm, gpu_stains_res); } + // Init ground cells texture + { + gpu_ground_cells_res = G_PushTexture2D( + gpu_perm, cl, + G_Format_R32_Uint, + cells_dims, + G_Layout_DirectQueue_ShaderReadWrite, + .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite, + .name = Lit("Ground cells") + ); + gpu_ground_cells = G_PushRWTexture2DRef(gpu_perm, gpu_ground_cells_res); + } + // Init air cells texture + { + gpu_air_cells_res = G_PushTexture2D( + gpu_perm, cl, + G_Format_R32_Uint, + cells_dims, + G_Layout_DirectQueue_ShaderReadWrite, + .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite, + .name = Lit("Air cells") + ); + gpu_air_cells = G_PushRWTexture2DRef(gpu_perm, gpu_air_cells_res); + } + // Init ground densities texture + { + gpu_ground_densities_res = G_PushTexture2D( + gpu_perm, cl, + G_Format_R32_Uint, + cells_dims, + G_Layout_DirectQueue_ShaderReadWrite, + .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite, + .name = Lit("Ground densities") + ); + gpu_ground_densities = G_PushRWTexture2DRef(gpu_perm, gpu_ground_densities_res); + } + // Init air densities texture + { + gpu_air_densities_res = G_PushTexture2D( + gpu_perm, cl, + G_Format_R32_Uint, + cells_dims, + G_Layout_DirectQueue_ShaderReadWrite, + .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite, + .name = Lit("Air densities") + ); + gpu_air_densities = G_PushRWTexture2DRef(gpu_perm, gpu_air_densities_res); + } // Init drynesses texture { gpu_drynesses_res = G_PushTexture2D( gpu_perm, cl, - // G_Format_R8_Uint, - // G_Format_R11G11B10_Float, - // G_Format_R10G10B10A2_Unorm, - // G_Format_R16_Float, G_Format_R32_Float, cells_dims, G_Layout_DirectQueue_ShaderReadWrite, @@ -476,22 +505,6 @@ void V_TickForever(WaveLaneCtx *lane) ); gpu_drynesses = G_PushRWTexture2DRef(gpu_perm, gpu_drynesses_res); } - // Init densities texture - { - gpu_densities_res = G_PushTexture2D( - gpu_perm, cl, - // G_Format_R8_Uint, - // G_Format_R11G11B10_Float, - // G_Format_R10G10B10A2_Unorm, - // G_Format_R16_Float, - G_Format_R32_Uint, - cells_dims, - G_Layout_DirectQueue_ShaderReadWrite, - .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite, - .name = Lit("Densities") - ); - gpu_densities = G_PushRWTexture2DRef(gpu_perm, gpu_densities_res); - } } G_CommitCommandList(cl); } @@ -610,10 +623,12 @@ void V_TickForever(WaveLaneCtx *lane) frame->pt_clamp_sampler = G_BasicPointClampSampler(); frame->pt_wrap_sampler = G_BasicPointWrapSampler(); frame->particles = gpu_particles; - frame->cells = gpu_cells; frame->stains = gpu_stains; + frame->ground_cells = gpu_ground_cells; + frame->air_cells = gpu_air_cells; + frame->ground_densities = gpu_ground_densities; + frame->air_densities = gpu_air_densities; frame->drynesses = gpu_drynesses; - frame->densities = gpu_densities; } ////////////////////////////// @@ -2523,43 +2538,84 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Push test emitter - if (frame->held_buttons[Button_G]) - // if (frame->held_buttons[Button_G] && !prev_frame->held_buttons[Button_G]) + // if (frame->held_buttons[Button_G]) + if (frame->held_buttons[Button_G] && !prev_frame->held_buttons[Button_G]) { - V_Emitter emitter = Zi; + // Debris + { + V_Emitter emitter = Zi; - emitter.kind = V_ParticleKind_Test; + emitter.kind = V_ParticleKind_Debris; - f32 angle = AngleFromVec2(frame->look); - // f32 angle = 0; - // f32 angle_spread = Tau * 0.25; - f32 angle_spread = Tau; - // f32 angle_spread = 0; + f32 angle = AngleFromVec2(frame->look); + // f32 angle = 0; + // f32 angle_spread = Tau * 0.25; + f32 angle_spread = Tau; + // f32 angle_spread = 0; - f32 speed = 25; - // f32 speed = 50; - // f32 speed = 1000; - f32 speed_spread = speed * 2; + // f32 speed = 25; + f32 speed = 50; + // f32 speed = 100; + f32 speed_spread = speed * 2; - emitter.pos.p0 = emitter.pos.p1 = frame->world_cursor; - emitter.speed.min = speed - speed_spread * 0.5; - emitter.speed.max = speed + speed_spread * 0.5; - emitter.angle.min = angle - angle_spread * 0.5; - emitter.angle.max = angle + angle_spread * 0.5; + emitter.pos.p0 = emitter.pos.p1 = frame->world_cursor; + emitter.speed.min = speed - speed_spread * 0.5; + emitter.speed.max = speed + speed_spread * 0.5; + emitter.angle.min = angle - angle_spread * 0.5; + emitter.angle.max = angle + angle_spread * 0.5; - // emitter.falloff.min = emitter.falloff.max = 0; + // emitter.falloff.min = emitter.falloff.max = 0; - // emitter.count = CeilF32(Kibi(64) * frame->dt); - // emitter.count = Mebi(16); - // emitter.count = Mebi(2); - // emitter.count = Kibi(32); - // emitter.count = Kibi(8); - emitter.count = Kibi(1); - // emitter.count = 128; - // emitter.count = 32; - // emitter.count = 1; + // emitter.count = CeilF32(Kibi(64) * frame->dt); + // emitter.count = Mebi(16); + // emitter.count = Mebi(2); + // emitter.count = Kibi(32); + // emitter.count = Kibi(8); + emitter.count = 128; + // emitter.count = 128; + // emitter.count = 32; + // emitter.count = 1; - V_PushParticles(emitter); + V_PushParticles(emitter); + } + + // Smoke + { + V_Emitter emitter = Zi; + + emitter.kind = V_ParticleKind_Smoke; + + f32 angle = AngleFromVec2(frame->look); + // f32 angle = 0; + // f32 angle_spread = Tau * 0.25; + f32 angle_spread = Tau; + // f32 angle_spread = 0; + + f32 speed = 25; + // f32 speed = 50; + // f32 speed = 50; + f32 speed_spread = speed * 2; + + emitter.pos.p0 = emitter.pos.p1 = frame->world_cursor; + emitter.speed.min = speed - speed_spread * 0.5; + emitter.speed.max = speed + speed_spread * 0.5; + emitter.angle.min = angle - angle_spread * 0.5; + emitter.angle.max = angle + angle_spread * 0.5; + + // emitter.falloff.min = emitter.falloff.max = 0; + + // emitter.count = CeilF32(Kibi(64) * frame->dt); + // emitter.count = Mebi(16); + // emitter.count = Mebi(2); + // emitter.count = Kibi(32); + emitter.count = Kibi(8); + // emitter.count = Kibi(1); + // emitter.count = 128; + // emitter.count = 32; + // emitter.count = 1; + + V_PushParticles(emitter); + } } @@ -4816,6 +4872,7 @@ void V_TickForever(WaveLaneCtx *lane) if (frame->should_clear_particles) { G_Compute(frame->cl, V_ClearParticlesCS, V_ThreadGroupSizeFromBufferSize(V_ParticlesCap)); + V.particle_seq = 0; } // Prepare screen RT diff --git a/src/pp/pp_vis/pp_vis_gpu.g b/src/pp/pp_vis/pp_vis_gpu.g index 38ff5209..e1207579 100644 --- a/src/pp/pp_vis/pp_vis_gpu.g +++ b/src/pp/pp_vis/pp_vis_gpu.g @@ -36,18 +36,22 @@ ComputeShader2D(V_PrepareShadeCS, 8, 8) ComputeShader2D(V_PrepareCellsCS, 8, 8) { V_SharedFrame frame = G_Dereference(V_ShaderConst_Frame)[0]; - RWTexture2D cells = G_Dereference(frame.cells); + RWTexture2D ground_cells = G_Dereference(frame.ground_cells); + RWTexture2D air_cells = G_Dereference(frame.air_cells); + RWTexture2D ground_densities = G_Dereference(frame.ground_densities); + RWTexture2D air_densities = G_Dereference(frame.air_densities); RWTexture2D drynesses = G_Dereference(frame.drynesses); - RWTexture2D densities = G_Dereference(frame.densities); Vec2 cells_pos = SV_DispatchThreadID + 0.5; - if (all(cells_pos < countof(cells))) + if (all(cells_pos < countof(air_cells))) { - // Clear cell - cells[cells_pos] = 0; + // Clear cells + ground_cells[cells_pos] = 0; + air_cells[cells_pos] = 0; - // Clear density - densities[cells_pos] = 0; + // Clear densities + ground_densities[cells_pos] = 0; + air_densities[cells_pos] = 0; // Increase dryness // TODO: Use simulation dt @@ -160,10 +164,12 @@ ComputeShader(V_SimParticlesCS, 64) { V_SharedFrame frame = G_Dereference(V_ShaderConst_Frame)[0]; RWStructuredBuffer particles = G_Dereference(frame.particles); - RWTexture2D cells = G_Dereference(frame.cells); RWTexture2D stains = G_Dereference(frame.stains); + RWTexture2D ground_cells = G_Dereference(frame.ground_cells); + RWTexture2D air_cells = G_Dereference(frame.air_cells); + RWTexture2D ground_densities = G_Dereference(frame.ground_densities); + RWTexture2D air_densities = G_Dereference(frame.air_densities); RWTexture2D drynesses = G_Dereference(frame.drynesses); - RWTexture2D densities = G_Dereference(frame.densities); Texture2D tiles = G_Dereference(frame.tiles); u32 particle_idx = SV_DispatchThreadID; @@ -176,11 +182,11 @@ ComputeShader(V_SimParticlesCS, 64) if (particle.kind != 0) { - u64 seed = MixU64(P_ParticleSimBasis ^ particle_idx); - f32 rand_offset = Norm16(seed >> 0); - f32 rand_angle = Norm16(seed >> 16); - f32 rand_speed = Norm16(seed >> 32); - f32 rand_falloff = Norm16(seed >> 48); + u64 seed0 = MixU64(P_ParticleSimBasis ^ particle_idx); + f32 rand_offset = Norm16(seed0 >> 0); + f32 rand_angle = Norm16(seed0 >> 16); + f32 rand_speed = Norm16(seed0 >> 32); + f32 rand_falloff = Norm16(seed0 >> 48); ////////////////////////////// //- Init @@ -201,6 +207,26 @@ ComputeShader(V_SimParticlesCS, 64) if (particle.kind > V_ParticleKind_None && particle.kind < V_ParticleKind_COUNT) { + ////////////////////////////// + //- Velocity effects + + { + // TODO: Separate particle basis for whisp effects + u64 seed1 = MixU64(seed0); + f32 rand_whisp = Norm16(seed1 >> 0); + + b32 is_whispy = particle.kind == V_ParticleKind_Smoke; + if (is_whispy) + { + f32 whisp = lerp(-1, 1, rand_whisp); + particle.velocity.x += whisp * cos(particle.life * 10); + particle.velocity.y += whisp * sin(particle.life * 10); + + // f32 whisp = lerp(0, Tau, rand_whisp) * frame.dt; + // particle.velocity = RotateVec2Angle(particle.velocity, whisp); + } + } + ////////////////////////////// //- Move @@ -288,18 +314,13 @@ ComputeShader(V_SimParticlesCS, 64) particle.velocity.y *= -1; } { - u64 collision_seed = MixU64s(seed, particle.collisions_count); + u64 collision_seed = MixU64s(seed0, particle.collisions_count); f32 rand_collision_angle = Norm16(collision_seed >> 0); f32 rand_collision_velocity = Norm16(collision_seed >> 16); f32 collision_angle = lerp(-0.05 * Tau, 0.05 * Tau, rand_collision_angle); // f32 collision_velocity_falloff = lerp(0, 1, rand_collision_velocity); f32 collision_velocity_falloff = 0; - f32 x = particle.velocity.x; - f32 y = particle.velocity.y; - f32 c = cos(collision_angle); - f32 s = sin(collision_angle); - particle.velocity.x = x * c - y * s; - particle.velocity.y = x * s + y * c; + particle.velocity = RotateVec2Angle(particle.velocity, collision_angle); particle.velocity *= 1.0f - collision_velocity_falloff; } ++particle.collisions_count; @@ -317,12 +338,21 @@ ComputeShader(V_SimParticlesCS, 64) //- Commit Vec2 cell_pos = mul(frame.af.world_to_cell, Vec3(particle.pos, 1)); - Vec2 screen_pos = mul(frame.af.world_to_screen, Vec3(particle.pos, 1)); - b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(cells)); - b32 is_in_screen = all(screen_pos >= 0) && all(screen_pos < frame.screen_dims); + Vec2 cell_screen_pos_p0 = mul(frame.af.world_to_screen, Vec3(mul(frame.af.cell_to_world, Vec3(floor(cell_pos), 1)), 1)); + Vec2 cell_screen_pos_p1 = mul(frame.af.world_to_screen, Vec3(mul(frame.af.cell_to_world, Vec3(ceil(cell_pos), 1)), 1)); + cell_screen_pos_p1 = max(cell_screen_pos_p1, cell_screen_pos_p0 + 1); - b32 should_draw = is_in_world && is_in_screen; - b32 should_stain = 0; + b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(air_cells)); + b32 is_visible = all(cell_screen_pos_p1 >= 0) && all(cell_screen_pos_p0 < frame.screen_dims); + + // TODO: Particle based flags + b32 is_stain_particle = particle.kind == V_ParticleKind_Debris; + b32 is_ground_particle = particle.kind == V_ParticleKind_Debris; + b32 is_air_particle = particle.kind == V_ParticleKind_Smoke; + + b32 should_stain = is_stain_particle && is_in_world; + b32 should_draw_ground = is_ground_particle && is_in_world && (is_visible || should_stain); + b32 should_draw_air = is_air_particle && is_in_world && is_visible; // // Stain // if (is_in_world) @@ -350,7 +380,7 @@ ComputeShader(V_SimParticlesCS, 64) // } // Draw - if (should_draw) + if (should_draw_ground || should_draw_air) { u32 packed = 0; packed |= (particle_idx & ((1 >> 24) - 1)) << 0; @@ -358,15 +388,24 @@ ComputeShader(V_SimParticlesCS, 64) StaticAssert(V_ParticlesCap <= (1 << 24)); // particle idx must fit in 24 bits StaticAssert(V_ParticleKind_COUNT <= 0xFF); // particle kind must fit in 8 bits - InterlockedMax(cells[cell_pos], packed); - InterlockedAdd(densities[cell_pos], 1); + if (should_draw_ground) + { + InterlockedMax(ground_cells[cell_pos], packed); + InterlockedAdd(ground_densities[cell_pos], 1); + } + + if (should_draw_air) + { + InterlockedMax(air_cells[cell_pos], packed); + InterlockedAdd(air_densities[cell_pos], 1); + } } // { // Vec2 cell_pos = mul(frame.af.world_to_cell, Vec3(particle.pos, 1)); // Vec2 screen_pos = mul(frame.af.world_to_screen, Vec3(particle.pos, 1)); // b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(cells)); - // b32 is_in_screen = all(screen_pos >= 0) && all(screen_pos < frame.screen_dims); + // b32 is_visible = all(screen_pos >= 0) && all(screen_pos < frame.screen_dims); // Vec4 color = particle.color; // color.a *= prev_exists; @@ -407,6 +446,9 @@ ComputeShader(V_SimParticlesCS, 64) // } // } + // Increment life + particle.life += frame.dt; + // Prune if (!is_in_world) { @@ -417,7 +459,6 @@ ComputeShader(V_SimParticlesCS, 64) { particle.kind = V_ParticleKind_None; } - particles[particle_idx] = particle; } } @@ -485,11 +526,13 @@ PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input) // Texture2D shade_tex = G_Dereference(frame.shade_ro); Texture2D albedo_tex = G_Dereference(frame.albedo_ro); RWTexture2D stains = G_Dereference(frame.stains); - RWTexture2D cells = G_Dereference(frame.cells); + RWTexture2D ground_cells = G_Dereference(frame.ground_cells); + RWTexture2D air_cells = G_Dereference(frame.air_cells); + RWTexture2D ground_densities = G_Dereference(frame.ground_densities); + RWTexture2D air_densities = G_Dereference(frame.air_densities); RWTexture2D drynesses = G_Dereference(frame.drynesses); Texture2D tiles = G_Dereference(frame.tiles); SamplerState clamp_sampler = G_Dereference(frame.pt_clamp_sampler); - RWTexture2D densities = G_Dereference(frame.densities); RWStructuredBuffer particles = G_Dereference(frame.particles); Vec2 screen_pos = input.sv_position.xy; @@ -501,7 +544,7 @@ PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input) Vec2 half_world_dims = Vec2(P_WorldPitch, P_WorldPitch) * 0.5; Vec2 world_bounds_screen_p0 = mul(frame.af.world_to_screen, Vec3(-half_world_dims.xy, 1)); Vec2 world_bounds_screen_p1 = mul(frame.af.world_to_screen, Vec3(half_world_dims.xy, 1)); - b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(cells)); + b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(ground_cells)); P_TileKind tile = tiles[tile_pos]; P_TileKind equipped_tile = frame.equipped_tile; @@ -632,45 +675,83 @@ PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input) } ////////////////////////////// - //- Particle + //- Ground particle // TODO: Remove this - // Vec4 particle_color = cells[cell_pos]; - // particle_color.rgb *= particle_color.a; - - Vec4 particle_color = 0; + Vec4 ground_particle_color = 0; { - u32 packed = cells[cell_pos]; - - V_ParticleKind kind = (V_ParticleKind)((packed >> 24) & 0xFF); - if (kind != V_ParticleKind_None) + Vec4 color = 0; { - u32 particle_idx = packed & ((1 << 24) - 1); - - if (particle_idx < V_ParticlesCap) + u32 packed = ground_cells[cell_pos]; + V_ParticleKind kind = (V_ParticleKind)((packed >> 24) & 0xFF); + if (kind != V_ParticleKind_None) { - if (kind == V_ParticleKind_Test) + u32 particle_idx = packed & ((1 << 24) - 1); + if (particle_idx < V_ParticlesCap) { u64 seed = MixU64(P_ParticleCompositeBasis ^ particle_idx); f32 rand_color = Norm16(seed >> 0); - - Vec4 color = Vec4(0.15, 0.15, 0.15, 1); - color.rgb += (rand_color - 0.5) * 0.025; - + if (kind == V_ParticleKind_Debris) { - f32 density = densities[cell_pos]; + color.rgb = Color_Orange.rgb; + } + else if (kind == V_ParticleKind_Smoke) + { + color.rgb = Vec3(0.15, 0.15, 0.15); + } + color.rgb += (rand_color - 0.5) * 0.025; + { + f32 density = ground_densities[cell_pos]; // f32 t = saturate(density / 10.0); f32 t = smoothstep(-10, 32, density); color.a = lerp(0, 0.85, t); } - - particle_color = color; } } } + ground_particle_color = color; + ground_particle_color.rgb *= ground_particle_color.a; + } - particle_color.rgb *= particle_color.a; + ////////////////////////////// + //- Air particle + + // TODO: Remove this + + Vec4 air_particle_color = 0; + { + Vec4 color = 0; + { + u32 packed = air_cells[cell_pos]; + V_ParticleKind kind = (V_ParticleKind)((packed >> 24) & 0xFF); + if (kind != V_ParticleKind_None) + { + u32 particle_idx = packed & ((1 << 24) - 1); + if (particle_idx < V_ParticlesCap) + { + u64 seed = MixU64(P_ParticleCompositeBasis ^ particle_idx); + f32 rand_color = Norm16(seed >> 0); + if (kind == V_ParticleKind_Debris) + { + color.rgb = Color_Orange.rgb; + } + else if (kind == V_ParticleKind_Smoke) + { + color.rgb = Vec3(0.15, 0.15, 0.15); + } + color.rgb += (rand_color - 0.5) * 0.025; + { + f32 density = air_densities[cell_pos]; + // f32 t = saturate(density / 10.0); + f32 t = smoothstep(-10, 32, density); + color.a = lerp(0, 0.85, t); + } + } + } + } + air_particle_color = color; + air_particle_color.rgb *= air_particle_color.a; } @@ -679,7 +760,8 @@ PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input) // world_color = BlendPremul(shade_color, world_color); world_color = BlendPremul(albedo_color, world_color); - world_color = BlendPremul(particle_color, world_color); + world_color = BlendPremul(ground_particle_color, world_color); + world_color = BlendPremul(air_particle_color, world_color); } ////////////////////////////// diff --git a/src/pp/pp_vis/pp_vis_shared.cgh b/src/pp/pp_vis/pp_vis_shared.cgh index 4bdd4b64..dc2f30f9 100644 --- a/src/pp/pp_vis/pp_vis_shared.cgh +++ b/src/pp/pp_vis/pp_vis_shared.cgh @@ -1,7 +1,7 @@ // #define V_ParticlesCap Kibi(128) // #define V_ParticlesCap Mebi(1) -// #define V_ParticlesCap Mebi(2) -#define V_ParticlesCap Mebi(16) +#define V_ParticlesCap Mebi(2) +// #define V_ParticlesCap Mebi(16) //////////////////////////////////////////////////////////// //~ State types @@ -146,10 +146,12 @@ Struct(V_SharedFrame) G_StructuredBufferRef emitters; G_RWStructuredBufferRef particles; - G_RWTexture2DRef cells; G_RWTexture2DRef stains; + G_RWTexture2DRef ground_cells; + G_RWTexture2DRef air_cells; + G_RWTexture2DRef ground_densities; + G_RWTexture2DRef air_densities; G_RWTexture2DRef drynesses; - G_RWTexture2DRef densities; G_StructuredBufferRef dverts; G_StructuredBufferRef quads; @@ -166,11 +168,17 @@ Enum(V_ParticleKind) { V_ParticleKind_None, + //- Ground particles V_ParticleKind_Blood, V_ParticleKind_Debris, - V_ParticleKind_Test, + + //- Air particles + V_ParticleKind_Smoke, V_ParticleKind_BulletTrail, + //- Test particles + V_ParticleKind_Test, + V_ParticleKind_COUNT, };