From 07d16048b2a002eefd5f9dc2c8ab80606b33f7d1 Mon Sep 17 00:00:00 2001 From: pkuzic Date: Sat, 10 Oct 2026 05:57:28 +0100 Subject: [PATCH] MONKEY (gfx seam W): retained character wetness is wet on every facing (wet_body); rain keeps the up-facing law Open graphics, cherry-pickable to lighting together with 517868a2. Co-Authored-By: Claude Opus 5.5 --- .../benilla-assets/src/shaders/wet_hook.wgsl | 18 ++++++++++++++++++ .../benilla-assets/src/shaders/wow_model.wgsl | 6 +++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/crates/benilla-assets/src/shaders/wet_hook.wgsl b/crates/benilla-assets/src/shaders/wet_hook.wgsl index c09903e4..8cbd1c6a 100644 --- a/crates/benilla-assets/src/shaders/wet_hook.wgsl +++ b/crates/benilla-assets/src/shaders/wet_hook.wgsl @@ -97,6 +97,24 @@ fn wet_surface(albedo: vec3, n: vec3, world_pos: vec3, exposure: return o; } +// MONKEY (motion verify 2): a character's wetness. `retained` (waded/swum/soaked, the +// monkey-surfacefx row) is NOT facing-weighted like rain on a surface: a body out of the water is +// wet all round, so its sides (legs, arms, flanks: n.y ~ 0) darken fully and keep a gloss. `rain` +// (exposed rain now) keeps the surface law (tops only). Same darken/saturate law as `wet_surface`. +const WET_BODY_UNDERSIDE: f32 = 0.85; // undersides a touch less (dripped off, shaded) +const WET_BODY_GLOSS: f32 = 0.7; // gloss weight on every facing at full retained wetness +fn wet_body(albedo: vec3, n: vec3, rain: f32, retained: f32) -> WetSurface { + var o: WetSurface; + let w_rain = wet_amount(n, 1.0, rain); + let w_body = clamp(retained, 0.0, 1.0) * mix(WET_BODY_UNDERSIDE, 1.0, smoothstep(-0.6, 0.4, n.y)); + let w = max(w_rain, w_body); + let luma = dot(albedo, vec3(0.299, 0.587, 0.114)); + let sat = max(mix(vec3(luma), albedo, 1.0 + 0.3 * w), vec3(0.0)); + o.albedo = sat * (1.0 - 0.36 * w); + o.boost = max(w_rain * smoothstep(0.35, 0.9, n.y), w_body * WET_BODY_GLOSS); + return o; +} + fn wet_hash(p: vec2) -> f32 { let q = fract(p * vec2(0.1031, 0.1030)); let r = q + dot(q, q.yx + 33.33); diff --git a/crates/benilla-assets/src/shaders/wow_model.wgsl b/crates/benilla-assets/src/shaders/wow_model.wgsl index 0d7b0207..892a08a4 100644 --- a/crates/benilla-assets/src/shaders/wow_model.wgsl +++ b/crates/benilla-assets/src/shaders/wow_model.wgsl @@ -1802,11 +1802,11 @@ fn fragment(in: WowVsOut, @builtin(front_facing) is_front: bool) -> WowFragOut { let surface_pass = surface_alpha_mode <= 1u || m.model_flags.y > 0.5; if (surface_slot != 0u && instance_wet > 0.0 && surface_pass && !is_wmo && !is_emissive && !is_mod && !is_mod2x && (u32(m.clutter_fade.z) & 4u) == 0u) { - var surface_frame = wow_light.monkey; // MONKEY: max of exposed rain and retained wetness, one darken/gloss application. + // MONKEY (motion verify 2): retained wetness is wet on every facing (`wet_body`); before, + // the rain law's facing weight left a swum body's vertical sides ~6 % darker and unglossed. let rain_wet = select(clamp(wow_light.monkey.wet_a.y, 0.0, 1.0) * wet_open, 0.0, wet_dry); - surface_frame.wet_a.y = max(rain_wet, instance_wet); - wet = wet_hook::wet_surface(rgb, n_lit, in.world_position.xyz, 1.0, surface_frame); + wet = wet_hook::wet_body(rgb, n_lit, rain_wet, instance_wet); } rgb = wet.albedo; if (wet.boost > 0.0) {