feat(client): cutaway modes — corridor / bottom-walls-low / both, C-key live toggle (T-1088)

Live-session two-minds resolution: the trippy sightline corridor stays as a
mode (candidate signature look); mode 1 drops any wall with a KNOWN non-wall
tile on its camera-far side to the stub (X2 bottom-walls read — the player
sees the room without walking to it); mode 2 combines. Bottom-wall flag rides
MultiMesh INSTANCE_CUSTOM.r, updated on paint and when newly-learned floors
promote camera-ward walls; camera-far directions derived from the live
WorldRoot basis, never hand-derived. Default stays corridor pending the
feel verdict.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-06 19:16:14 +02:00
co-authored by Claude Fable 5
parent 2db7dd25e1
commit e32a041778
4 changed files with 113 additions and 4 deletions
@@ -33,13 +33,20 @@ uniform float u_cut_height = 0.75; // SandboxConstants.CUT_HEIGHT — the
uniform float u_corridor_half_w = 1.4; // SandboxConstants.CUT_CORRIDOR_HALF_W
uniform float u_cut_band = 0.75; // SandboxConstants.CUT_BAND — falloff band
uniform float u_cut_reach = 4.4; // per-frame: WALL_H / tan(camera pitch)
// 0 = sightline corridor, 1 = bottom walls low, 2 = both (live-toggled, C key).
uniform int u_cutaway_mode = 0;
uniform vec3 u_base_albedo : source_color = vec3(0.66, 0.64, 0.60);
varying vec3 v_world_pos;
// Bottom-wall flag (INSTANCE_CUSTOM.r, set by GreyboxWorld): 1.0 when a KNOWN
// non-wall tile sits on this wall's camera-far side — the wall would occlude
// interior the player should see, X2-style.
varying flat float v_bottom;
void vertex() {
// MODEL_MATRIX folds in the per-instance MultiMesh transform.
v_world_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
v_bottom = INSTANCE_CUSTOM.r;
}
void fragment() {
@@ -50,7 +57,14 @@ void fragment() {
float near_f = smoothstep(-0.25, 0.75, to_wall.y);
// Far gate: corridor ends where a WALL_H wall can no longer occlude.
float far_f = 1.0 - smoothstep(u_cut_reach, u_cut_reach + u_cut_band, to_wall.y);
float allowed = mix(u_wall_h, u_cut_height, lateral * near_f * far_f);
float corridor_f = lateral * near_f * far_f;
float cut_f = corridor_f;
if (u_cutaway_mode == 1) {
cut_f = v_bottom;
} else if (u_cutaway_mode == 2) {
cut_f = max(corridor_f, v_bottom);
}
float allowed = mix(u_wall_h, u_cut_height, cut_f);
if (v_world_pos.y > allowed) {
discard;
}