From 88f37a4bbb0a0a911e40704f8f04cd581dab36e6 Mon Sep 17 00:00:00 2001 From: jacob Date: Tue, 17 Feb 2026 08:22:25 -0600 Subject: [PATCH] dryness --- src/base/base_math.h | 3 ++ src/base/base_shader.gh | 3 ++ src/pp/pp_vis/pp_vis_core.c | 23 ++++++++++++--- src/pp/pp_vis/pp_vis_gpu.g | 50 +++++++++++++++++++++------------ src/pp/pp_vis/pp_vis_shared.cg | 31 ++++++++------------ src/pp/pp_vis/pp_vis_shared.cgh | 28 ++++++++++++------ 6 files changed, 87 insertions(+), 51 deletions(-) diff --git a/src/base/base_math.h b/src/base/base_math.h index e16cb966..7b08795a 100644 --- a/src/base/base_math.h +++ b/src/base/base_math.h @@ -29,6 +29,7 @@ Union(Vec2U64) { struct { u64 x, y; }; struct { u64 r, g; }; u64 v[2]; }; Struct(Vec2Array) { Vec2 *points; u64 count; }; +#define CompVec2(x, y) { (x), (y) } #define VEC2(x, y) (Vec2) { (x), (y) } #define VEC2F64(x, y) (Vec2F64) { (x), (y) } #define VEC2I32(x, y) (Vec2I32) { (x), (y) } @@ -54,6 +55,7 @@ Union(Vec3U64) { struct { u64 x, y, z; }; struct { u64 r, g, b; }; u64 v[3]; }; Struct(Vec3Array) { Vec3 *points; u64 count; }; +#define CompVec3(x, y, z) { (x), (y), (z) } #define VEC3(x, y, z) (Vec3) { (x), (y), (z) } #define VEC3F64(x, y, z) (Vec3F64) { (x), (y), (z) } #define VEC3I32(x, y, z) (Vec3I32) { (x), (y), (z) } @@ -79,6 +81,7 @@ Union(Vec4U64) { struct { u64 x, y, z, w; }; struct { u64 r, g, b, a; }; u64 v[4 Struct(Vec4Array) { Vec4 *points; u64 count; }; +#define CompVec4(x, y, z, w) { (x), (y), (z), (w) } #define VEC4(x, y, z, w) (Vec4) { (x), (y), (z), (w) } #define VEC4F64(x, y, z, w) (Vec4F64) { (x), (y), (z), (w) } #define VEC4I32(x, y, z, w) (Vec4I32) { (x), (y), (z), (w) } diff --git a/src/base/base_shader.gh b/src/base/base_shader.gh index 9e025a45..1993dd2e 100644 --- a/src/base/base_shader.gh +++ b/src/base/base_shader.gh @@ -47,6 +47,9 @@ u32 countof(T arr[N]) //~ C -> HLSL interoperability stubs //- Constructors +#define CompVec2(x, y) { (x), (y) } +#define CompVec3(x, y, z) { (x), (y), (z) } +#define CompVec4(x, y, z, w) { (x), (y), (z), (w) } #define VEC2(...) Vec2(__VA_ARGS__) #define VEC3(...) Vec3(__VA_ARGS__) #define VEC4(...) Vec4(__VA_ARGS__) diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 526831cc..f2f5e6b5 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -395,6 +395,7 @@ void V_TickForever(WaveLaneCtx *lane) G_ResourceHandle gpu_particle_cell_resources[V_ParticleLayer_COUNT]; G_ResourceHandle gpu_particle_density_resources[V_ParticleLayer_COUNT]; G_ResourceHandle gpu_stains_res = Zi; + G_ResourceHandle gpu_dry_stains_res = Zi; G_ResourceHandle gpu_drynesses_res = Zi; G_ResourceHandle gpu_occluders_res = Zi; @@ -403,6 +404,7 @@ void V_TickForever(WaveLaneCtx *lane) G_RWTexture2DRef gpu_particle_cells[V_ParticleLayer_COUNT]; G_RWTexture2DRef gpu_particle_densities[V_ParticleLayer_COUNT]; G_RWTexture2DRef gpu_stains = Zi; + G_RWTexture2DRef gpu_dry_stains = Zi; G_RWTexture2DRef gpu_drynesses = Zi; G_RWTexture2DRef gpu_occluders = Zi; { @@ -473,6 +475,18 @@ void V_TickForever(WaveLaneCtx *lane) ); gpu_stains = G_PushRWTexture2DRef(gpu_perm, gpu_stains_res); } + //- Init dry stains texture + { + gpu_dry_stains_res = G_PushTexture2D( + gpu_perm, cl, + G_Format_R16G16B16A16_Float, + cells_dims, + G_Layout_DirectQueue_ShaderReadWrite, + .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite, + .name = Lit("Dry stains") + ); + gpu_dry_stains = G_PushRWTexture2DRef(gpu_perm, gpu_dry_stains_res); + } //- Init dryness texture { gpu_drynesses_res = G_PushTexture2D( @@ -622,6 +636,7 @@ void V_TickForever(WaveLaneCtx *lane) frame->tiles = gpu_tiles; frame->particles = gpu_particles; frame->stains = gpu_stains; + frame->dry_stains = gpu_dry_stains; frame->drynesses = gpu_drynesses; frame->occluders = gpu_occluders; } @@ -2699,14 +2714,14 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Push test explosion - 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]) { - // Debris + // Fire { V_Emitter emitter = Zi; - emitter.kind = V_ParticleKind_Debris; + emitter.kind = V_ParticleKind_Fire; f32 angle = AngleFromVec2(frame->look); // f32 angle = 0; diff --git a/src/pp/pp_vis/pp_vis_gpu.g b/src/pp/pp_vis/pp_vis_gpu.g index 43785e44..f8a254de 100644 --- a/src/pp/pp_vis/pp_vis_gpu.g +++ b/src/pp/pp_vis/pp_vis_gpu.g @@ -16,7 +16,7 @@ Vec4 V_ColorFromParticle(V_ParticleDesc desc, u32 particle_idx, u32 density) u64 seed = MixU64(V_ParticleColorBasis ^ particle_idx); f32 rand_color = Norm16(seed >> 0); - result = desc.color; + result = desc.base_color; // Apply density { @@ -49,10 +49,6 @@ Vec4 V_ColorFromParticle(V_ParticleDesc desc, u32 particle_idx, u32 density) } result.rgb = result.rgb + (rand_color - 0.5) * 0.05; - // result.a += (rand_alpha - 0.5) * 0.025; - // result.a *= rand_alpha; - - // Apply dryness return result; } @@ -85,6 +81,7 @@ ComputeShader2D(V_PrepareCellsCS, 8, 8) V_SharedFrame frame = G_Dereference(V_GpuConst_Frame)[0]; Texture2D tiles = G_Dereference(frame.tiles); RWTexture2D stains = G_Dereference(frame.stains); + RWTexture2D dry_stains = G_Dereference(frame.dry_stains); RWTexture2D drynesses = G_Dereference(frame.drynesses); RWTexture2D occluders = G_Dereference(frame.occluders); @@ -108,7 +105,8 @@ ComputeShader2D(V_PrepareCellsCS, 8, 8) //- Reset particle layers - Vec4 new_stain = 0; + Vec4 over_stain = 0; + Vec4 over_dry_stain = 0; for (V_ParticleLayer layer = (V_ParticleLayer)0; layer < V_ParticleLayer_COUNT; layer += (V_ParticleLayer)1) { RWTexture2D cells = G_Dereference(frame.particle_cells[layer]); @@ -120,9 +118,15 @@ ComputeShader2D(V_PrepareCellsCS, 8, 8) V_ParticleDesc desc = V_DescFromParticleKind(particle_kind); u32 density = densities[cell_pos]; u32 particle_idx = packed & ((1 << 24) - 1); - Vec4 particle_color = V_ColorFromParticle(desc, particle_idx, density); - particle_color.rgb *= particle_color.a; - new_stain = BlendPremul(particle_color, new_stain); + + Vec4 base_color = V_ColorFromParticle(desc, particle_idx, density); + Vec4 dry_color = base_color * desc.dry_factor; + + base_color.rgb *= base_color.a; + dry_color.rgb *= dry_color.a; + + over_stain = BlendPremul(base_color, over_stain); + over_dry_stain = BlendPremul(dry_color, over_dry_stain); } cells[cell_pos] = 0; densities[cell_pos] = 0; @@ -133,18 +137,28 @@ ComputeShader2D(V_PrepareCellsCS, 8, 8) if (frame.should_clear_particles) { stains[cell_pos] = 0; + dry_stains[cell_pos] = 0; drynesses[cell_pos] = 0; } - else if (new_stain.a > 0) + else if (over_stain.a > 0) { - Vec4 stain = stains[cell_pos]; - stain = BlendPremul(new_stain, stain); + Vec4 stain = dry_stains[cell_pos]; + Vec4 dry_stain = max(dry_stains[cell_pos], 0); + + stain = BlendPremul(over_stain, stain); + dry_stain = BlendPremul(over_dry_stain, dry_stain); + stains[cell_pos] = stain; + dry_stains[cell_pos] = dry_stain; drynesses[cell_pos] = 0; } else { - f32 dry_rate = frame.dt * 0.1; + f32 dry_rate = saturate(frame.dt * 0.1); + + Vec4 before_stain = stains[cell_pos]; + Vec4 before_dry_stain = dry_stains[cell_pos]; + drynesses[cell_pos] = lerp(drynesses[cell_pos], 1, dry_rate); } } @@ -581,6 +595,7 @@ ComputeShader2D(V_CompositeCS, 8, 8) Texture2D albedo_tex = G_Dereference(frame.albedo_ro); RWTexture2D screen_tex = G_Dereference(frame.screen_rw); RWTexture2D stains = G_Dereference(frame.stains); + RWTexture2D dry_stains = G_Dereference(frame.dry_stains); RWTexture2D drynesses = G_Dereference(frame.drynesses); Texture2D tiles = G_Dereference(frame.tiles); RWStructuredBuffer particles = G_Dereference(frame.particles); @@ -699,11 +714,10 @@ ComputeShader2D(V_CompositeCS, 8, 8) // FIXME: Stain Vec4 stain_color = 0; { - Vec4 orig_stain = stains[cell_pos]; - - // FIXME: Dryness - // f32 dryness = drynesses[cell_pos]; - stain_color = orig_stain; + Vec4 wet_stain = stains[cell_pos]; + Vec4 dry_stain = dry_stains[cell_pos]; + f32 dryness = drynesses[cell_pos]; + stain_color = max(lerp(wet_stain, dry_stain, dryness), 0); } Vec4 ground_particle_color = 0; diff --git a/src/pp/pp_vis/pp_vis_shared.cg b/src/pp/pp_vis/pp_vis_shared.cg index 875852d1..2419a6f2 100644 --- a/src/pp/pp_vis/pp_vis_shared.cg +++ b/src/pp/pp_vis/pp_vis_shared.cg @@ -11,47 +11,37 @@ V_ParticleDesc V_DescFromParticleKind(V_ParticleKind kind) V_ParticleDesc result; { PERSIST Readonly V_ParticleFlag flags[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, stain_rate, pen_rate, lifetime, r, g, b, a) flags, + #define X(name, flags, layer, stain_rate, pen_rate, lifetime, base_color, dry_factor) flags, V_ParticlesXList(X) #undef X }; PERSIST Readonly V_ParticleLayer layers[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, stain_rate, pen_rate, lifetime, r, g, b, a) layer, + #define X(name, flags, layer, stain_rate, pen_rate, lifetime, base_color, dry_factor) layer, V_ParticlesXList(X) #undef X }; PERSIST Readonly f32 stain_rates[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, stain_rate, pen_rate, lifetime, r, g, b, a) stain_rate, + #define X(name, flags, layer, stain_rate, pen_rate, lifetime, base_color, dry_factor) stain_rate, V_ParticlesXList(X) #undef X }; PERSIST Readonly f32 pen_rates[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, stain_rate, pen_rate, lifetime, r, g, b, a) pen_rate, + #define X(name, flags, layer, stain_rate, pen_rate, lifetime, base_color, dry_factor) pen_rate, V_ParticlesXList(X) #undef X }; PERSIST Readonly f32 lifetimes[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, stain_rate, pen_rate, lifetime, r, g, b, a) lifetime, + #define X(name, flags, layer, stain_rate, pen_rate, lifetime, base_color, dry_factor) lifetime, V_ParticlesXList(X) #undef X }; - PERSIST Readonly f32 r[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, stain_rate, pen_rate, lifetime, r, g, b, a) r, + PERSIST Readonly Vec4 base_colors[V_ParticleKind_COUNT] = { + #define X(name, flags, layer, stain_rate, pen_rate, lifetime, base_color, dry_factor) base_color, V_ParticlesXList(X) #undef X }; - PERSIST Readonly f32 g[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, stain_rate, pen_rate, lifetime, r, g, b, a) g, - V_ParticlesXList(X) - #undef X - }; - PERSIST Readonly f32 b[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, stain_rate, pen_rate, lifetime, r, g, b, a) b, - V_ParticlesXList(X) - #undef X - }; - PERSIST Readonly f32 a[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, stain_rate, pen_rate, lifetime, r, g, b, a) a, + PERSIST Readonly Vec4 dry_factor[V_ParticleKind_COUNT] = { + #define X(name, flags, layer, stain_rate, pen_rate, lifetime, base_color, dry_factor) dry_factor, V_ParticlesXList(X) #undef X }; @@ -61,7 +51,8 @@ V_ParticleDesc V_DescFromParticleKind(V_ParticleKind kind) result.stain_rate = stain_rates[kind]; result.pen_rate = pen_rates[kind]; result.lifetime = lifetimes[kind]; - result.color = LinearFromSrgb(VEC4(r[kind], g[kind], b[kind], a[kind])); + result.base_color = LinearFromSrgb(base_colors[kind]); + result.dry_factor = LinearFromSrgb(dry_factor[kind]); } return result; } diff --git a/src/pp/pp_vis/pp_vis_shared.cgh b/src/pp/pp_vis/pp_vis_shared.cgh index 9b0d7334..16ca6419 100644 --- a/src/pp/pp_vis/pp_vis_shared.cgh +++ b/src/pp/pp_vis/pp_vis_shared.cgh @@ -53,7 +53,8 @@ Enum(V_ParticleLayer) /* Layer */ V_ParticleLayer_Ground, \ /* Stain rate, pen chance */ 30, 0, \ /* Lifetime */ Inf, \ - /* Base color */ 0, 0, 0, 0 \ + /* Base color */ CompVec4(0, 0, 0, 0), \ + /* Dry color factor */ CompVec4(1, 1, 1, 1) \ ) \ \ /* Ground particles */ \ @@ -63,7 +64,8 @@ Enum(V_ParticleLayer) /* Layer */ V_ParticleLayer_Ground, \ /* Stain rate, pen chance */ 100, 0.25, \ /* Lifetime */ Inf, \ - /* Base color */ 0.5, 0.1, 0.1, 0.05 \ + /* Base color */ CompVec4(0.5, 0.1, 0.1, 0.05), \ + /* Dry color factor */ CompVec4(0.5, 0.5, 0.5, 1) \ ) \ X( \ /* Name */ BloodDebris, \ @@ -71,7 +73,8 @@ Enum(V_ParticleLayer) /* Layer */ V_ParticleLayer_Mid, \ /* Stain rate, pen chance */ 30, 0, \ /* Lifetime */ Inf, \ - /* Base color */ 0.5, 0.1, 0.1, 0.8 \ + /* Base color */ CompVec4(0.5, 0.1, 0.1, 0.8), \ + /* Dry color factor */ CompVec4(1, 1, 1, 1) \ ) \ X( \ /* Name */ Debris, \ @@ -79,7 +82,8 @@ Enum(V_ParticleLayer) /* Layer */ V_ParticleLayer_Mid, \ /* Stain rate, pen chance */ 0, 0, \ /* Lifetime */ Inf, \ - /* Base color */ 0.4, 0.3, 0.2, 1 \ + /* Base color */ CompVec4(0.4, 0.3, 0.2, 1), \ + /* Dry color factor */ CompVec4(1, 1, 1, 1) \ ) \ X( \ /* Name */ Fire, \ @@ -87,7 +91,8 @@ Enum(V_ParticleLayer) /* Layer */ V_ParticleLayer_Mid, \ /* Stain rate, pen chance */ 0, 0, \ /* Lifetime */ Inf, \ - /* Base color */ 2, 0.5, 0, 1 \ + /* Base color */ CompVec4(2, 0.5, 0, 1), \ + /* Dry color factor */ CompVec4(0.2, 0.1, 0.0, 1) \ ) \ \ /* Air particles */ \ @@ -97,7 +102,8 @@ Enum(V_ParticleLayer) /* Layer */ V_ParticleLayer_Mid, \ /* Stain rate, pen chance */ 0, 0, \ /* Lifetime */ 0.075, \ - /* Base color */ 0.8, 0.6, 0.2, 0.25 \ + /* Base color */ CompVec4(0.8, 0.6, 0.2, 0.25), \ + /* Dry color factor */ CompVec4(1, 1, 1, 1) \ ) \ X( \ /* Name */ Smoke, \ @@ -105,7 +111,8 @@ Enum(V_ParticleLayer) /* Layer */ V_ParticleLayer_Air, \ /* Stain rate, pen chance */ 0, 0, \ /* Lifetime */ Inf, \ - /* Base color */ 0.25, 0.25, 0.25, 0.75 \ + /* Base color */ CompVec4(0.25, 0.25, 0.25, 0.75), \ + /* Dry color factor */ CompVec4(1, 1, 1, 1) \ ) \ \ /* Test particles */ \ @@ -115,7 +122,8 @@ Enum(V_ParticleLayer) /* Layer */ V_ParticleLayer_Mid, \ /* Stain rate, pen chance */ 0, 0, \ /* Lifetime */ Inf, \ - /* Base color */ 1, 1, 0, 1 \ + /* Base color */ CompVec4(1, 1, 0, 1), \ + /* Dry color factor */ CompVec4(1, 1, 1, 1) \ ) \ /* ----------------------------------------------------------------------------------------------------------------------------------- */ @@ -160,7 +168,8 @@ Struct(V_ParticleDesc) f32 stain_rate; f32 pen_rate; f32 lifetime; - Vec4 color; + Vec4 base_color; + Vec4 dry_factor; }; #if IsCpu @@ -341,6 +350,7 @@ Struct(V_SharedFrame) G_RWStructuredBufferRef particles; G_RWTexture2DRef stains; + G_RWTexture2DRef dry_stains; G_RWTexture2DRef drynesses; G_RWTexture2DRef occluders;