From 2d31d490d1711c92fccd93382babf0ede352ac47 Mon Sep 17 00:00:00 2001 From: Erik Date: Tue, 26 May 2026 07:52:55 +0200 Subject: [PATCH] =?UTF-8?q?feat(render):=20Phase=20A8=20=E2=80=94=20portal?= =?UTF-8?q?=5Fstencil=20vert/frag=20shaders?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Minimal pair for the indoor-cell stencil pipeline (#78). Vert transforms world-space portal polygon vertices through uViewProjection; includes a near-zero pos.w guard for coplanar-camera robustness (matches WB pattern). Frag either passes through gl_FragCoord.z or writes gl_FragDepth=1.0 based on uWriteFarDepth; FragColor declared but suppressed via ColorMask on the CPU side. Matches WorldBuilder's PortalStencil.vert/.frag at references/WorldBuilder/Chorizite.OpenGLSDLBackend/Shaders/. Uses #version 430 core consistent with acdream's mesh_modern shaders. Deployed to bin/ via existing Rendering\Shaders\*.* .csproj glob. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Rendering/Shaders/portal_stencil.frag | 34 +++++++++++++++++++ .../Rendering/Shaders/portal_stencil.vert | 25 ++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 src/AcDream.App/Rendering/Shaders/portal_stencil.frag create mode 100644 src/AcDream.App/Rendering/Shaders/portal_stencil.vert diff --git a/src/AcDream.App/Rendering/Shaders/portal_stencil.frag b/src/AcDream.App/Rendering/Shaders/portal_stencil.frag new file mode 100644 index 0000000..ba71c36 --- /dev/null +++ b/src/AcDream.App/Rendering/Shaders/portal_stencil.frag @@ -0,0 +1,34 @@ +#version 430 core +// +// Phase A8 — portal stencil mark + far-depth punch. +// +// uWriteFarDepth = 0 → pass through gl_FragCoord.z (used for the +// stencil mark pass; depth mask is off anyway). +// uWriteFarDepth != 0 → write gl_FragDepth = 1.0 (the far-depth punch +// pass; depth mask is on, color is off). +// +// Matches WorldBuilder's PortalStencil.frag at +// references/WorldBuilder/Chorizite.OpenGLSDLBackend/Shaders/PortalStencil.frag + +out vec4 FragColor; + +uniform int uWriteFarDepth; + +void main() +{ + if (uWriteFarDepth != 0) + { + // Write far depth to clear the depth buffer in the portal region. + // This punches through the building exterior's depth so interior + // geometry at any depth can be rendered through the stencil mask. + gl_FragDepth = 1.0; + } + else + { + gl_FragDepth = gl_FragCoord.z; + } + + // Color writes are suppressed via ColorMask(false) on the CPU side. + // Output is required by GLSL but will not be written to the framebuffer. + FragColor = vec4(0.0); +} diff --git a/src/AcDream.App/Rendering/Shaders/portal_stencil.vert b/src/AcDream.App/Rendering/Shaders/portal_stencil.vert new file mode 100644 index 0000000..adb4d60 --- /dev/null +++ b/src/AcDream.App/Rendering/Shaders/portal_stencil.vert @@ -0,0 +1,25 @@ +#version 430 core +// +// Phase A8 — portal stencil mark + far-depth punch. +// +// Position is in WORLD space (pipeline transforms cell-local portal +// polygon vertices through cell.WorldTransform on the CPU before +// uploading to the VBO). Output is clip space via uViewProjection. + +layout(location = 0) in vec3 aPosition; + +uniform mat4 uViewProjection; + +void main() +{ + vec4 pos = uViewProjection * vec4(aPosition, 1.0); + + // Prevent near-zero clipping issues when the camera is perfectly + // coplanar with the portal polygon. + if (abs(pos.w) < 0.001) + { + pos.w = pos.w < 0.0 ? -0.001 : 0.001; + } + + gl_Position = pos; +}