#version 430 core // Campaign V slice V6l: retail's invisible portal depth write, moved out of // PortalDepthMaskRenderer's inline GLSL string and into the shader tree so both // backends compile it from one source. The BODY is the one that renderer has // carried since BR-2 and #117; only how its inputs arrive changed. // // Three input moves, each because Vulkan GLSL has no default uniform block: // // uPlaneCount / uPlanes[8] -> the TerrainClip UBO at binding=2, which is // already exactly this shape (int count + 8 // clip-space half-planes) and is already // declared identically by terrain_modern.vert // and sky.vert. Retail clips the portal polygon // on the CPU against the installed view // (polyClipFinish); we apply the SAME view // region through gl_ClipDistance, so the depth // write lands only inside the slice region. // uForceFarZ -> uRenderPass, the shared push block's pass // selector. This shader's two passes ARE seal // (retail maxZ2, true projected depth) and punch // (retail maxZ1, far-plane z). // uDepthBias / EyeCapN -> uParamA / uParamB. layout(location = 0) in vec3 aPos; // Loose uniforms for the GL dialect. Under Vulkan the compiler drops these // declarations and the injected preamble #defines each name onto its member of // the shared 96-byte push block (tools/ShaderCompiler/VulkanGlslPreamble.cs). uniform mat4 uViewProjection; uniform int uRenderPass; // 0 = seal (retail maxZ2), 1 = punch (retail maxZ1) uniform float uParamA; // #117 mark-pass NDC bias toward the viewer uniform float uParamB; // #129 eye-span cap x near plane layout(std140, ACDREAM_UBO_SET binding = 2) uniform TerrainClip { int uTerrainClipCount; vec4 uTerrainClipPlanes[8]; }; // Core profile: redeclare gl_PerVertex so writing gl_ClipDistance[] is legal // (mirrors terrain_modern.vert and sky.vert). Sized 8 to match the // ClipFrame.MaxPlanes budget and GL's guaranteed GL_MAX_CLIP_DISTANCES >= 8. out gl_PerVertex { vec4 gl_Position; float gl_ClipDistance[8]; }; void main() { vec4 clipPos = uViewProjection * vec4(aPos, 1.0); for (int i = 0; i < 8; i++) gl_ClipDistance[i] = (i < uTerrainClipCount) ? dot(uTerrainClipPlanes[i], clipPos) : 1.0; if (uRenderPass == 1) { clipPos.z = clipPos.w * 0.99999988; // retail far-z punch constant (0x0059bc90 tail) } else if (uParamA > 0.0) { // #117 mark-pass bias, #129 eye-space cap. clipPos.w = eye depth d; // an NDC bias b spans ~b*d*d/near meters of eye depth, so the // constant-NDC form alone reached METERS at distance (door-shaped // leaks through hills/houses). Keep in sync with // PortalDepthMaskRenderer.MarkBiasNdc. float biasNdc = min(uParamA, uParamB / max(clipPos.w * clipPos.w, 1e-6)); clipPos.z -= biasNdc * clipPos.w; } gl_Position = clipPos; }