From 3c108a0d68187ff71ae38f2aab3aacca890af6cd Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 9 May 2026 08:45:22 +0200 Subject: [PATCH] phase(N.5b) Task 4: terrain_modern.vert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vertex shader for the modern terrain dispatcher. Bit-identical math to today's terrain.vert (Phase 3c per-cell mesh + Phase G AdjustPlanes lighting). The only structural change is the version + bindless extension preamble — sampler access stays a regular sampler2DArray uniform; bindless-ness is invisible at the GLSL level. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Rendering/Shaders/terrain_modern.vert | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 src/AcDream.App/Rendering/Shaders/terrain_modern.vert diff --git a/src/AcDream.App/Rendering/Shaders/terrain_modern.vert b/src/AcDream.App/Rendering/Shaders/terrain_modern.vert new file mode 100644 index 0000000..2f2f822 --- /dev/null +++ b/src/AcDream.App/Rendering/Shaders/terrain_modern.vert @@ -0,0 +1,115 @@ +#version 460 core +#extension GL_ARB_bindless_texture : require + +// Phase N.5b: terrain shader on the modern bindless dispatcher. +// Math identical to terrain.vert (Phase 3c per-cell mesh + Phase G AdjustPlanes +// lighting). The only structural change is the version + bindless extension +// — sampler access in the fragment stage is unchanged at the GLSL level. + +layout(location = 0) in vec3 aPos; +layout(location = 1) in vec3 aNormal; +layout(location = 2) in uvec4 aPacked0; +layout(location = 3) in uvec4 aPacked1; +layout(location = 4) in uvec4 aPacked2; +layout(location = 5) in uvec4 aPacked3; + +uniform mat4 uView; +uniform mat4 uProjection; + +struct Light { + vec4 posAndKind; + vec4 dirAndRange; + vec4 colorAndIntensity; + vec4 coneAngleEtc; +}; +layout(std140, binding = 1) uniform SceneLighting { + Light uLights[8]; + vec4 uCellAmbient; + vec4 uFogParams; + vec4 uFogColor; + vec4 uCameraAndTime; +}; + +out vec2 vBaseUV; +out vec3 vWorldNormal; +out vec3 vWorldPos; +out vec3 vLightingRGB; +out vec4 vOverlay0; +out vec4 vOverlay1; +out vec4 vOverlay2; +out vec4 vRoad0; +out vec4 vRoad1; +flat out float vBaseTexIdx; + +const float MIN_FACTOR = 0.0; + +vec4 unpackOverlayLayer(uint texIdxU, uint alphaIdxU, uint rotIdx, vec2 baseUV) { + float texIdx = float(texIdxU); + float alphaIdx = float(alphaIdxU); + if (texIdx >= 254.0) texIdx = -1.0; + if (alphaIdx >= 254.0) alphaIdx = -1.0; + + vec2 rotatedUV = baseUV; + if (rotIdx == 1u) rotatedUV = vec2(1.0 - baseUV.y, baseUV.x); + else if (rotIdx == 2u) rotatedUV = vec2(1.0 - baseUV.x, 1.0 - baseUV.y); + else if (rotIdx == 3u) rotatedUV = vec2( baseUV.y, 1.0 - baseUV.x); + + return vec4(rotatedUV.x, rotatedUV.y, texIdx, alphaIdx); +} + +void main() { + uint rotOvl0 = (aPacked3.x >> 2u) & 3u; + uint rotOvl1 = (aPacked3.x >> 4u) & 3u; + uint rotOvl2 = (aPacked3.x >> 6u) & 3u; + uint rotRd0 = aPacked3.y & 3u; + uint rotRd1 = (aPacked3.y >> 2u) & 3u; + uint splitDir= (aPacked3.y >> 4u) & 1u; + + int vIdx = gl_VertexID % 6; + int corner = 0; + if (splitDir == 0u) { + // SWtoNE order: BL, BR, TR, BL, TR, TL → corners 0, 1, 2, 0, 2, 3 + if (vIdx == 0) corner = 0; + else if (vIdx == 1) corner = 1; + else if (vIdx == 2) corner = 2; + else if (vIdx == 3) corner = 0; + else if (vIdx == 4) corner = 2; + else corner = 3; + } else { + // SEtoNW order: BL, BR, TL, BR, TR, TL → corners 0, 1, 3, 1, 2, 3 + if (vIdx == 0) corner = 0; + else if (vIdx == 1) corner = 1; + else if (vIdx == 2) corner = 3; + else if (vIdx == 3) corner = 1; + else if (vIdx == 4) corner = 2; + else corner = 3; + } + + vec2 baseUV; + if (corner == 0) baseUV = vec2(0.0, 1.0); + else if (corner == 1) baseUV = vec2(1.0, 1.0); + else if (corner == 2) baseUV = vec2(1.0, 0.0); + else baseUV = vec2(0.0, 0.0); + + vBaseUV = baseUV; + vWorldPos = aPos; + vWorldNormal = normalize(aNormal); + + // Retail AdjustPlanes bake (terrain.vert:124-134 — identical math). + vec3 sunDir = uLights[0].dirAndRange.xyz; + vec3 sunCol = uLights[0].colorAndIntensity.xyz * uLights[0].colorAndIntensity.w; + float L = max(dot(vWorldNormal, -sunDir), MIN_FACTOR); + vLightingRGB = sunCol * L + uCellAmbient.xyz; + + float baseTex = float(aPacked0.x); + if (baseTex >= 254.0) baseTex = -1.0; + vBaseTexIdx = baseTex; + + vOverlay0 = unpackOverlayLayer(aPacked0.z, aPacked0.w, rotOvl0, baseUV); + vOverlay1 = unpackOverlayLayer(aPacked1.x, aPacked1.y, rotOvl1, baseUV); + vOverlay2 = unpackOverlayLayer(aPacked1.z, aPacked1.w, rotOvl2, baseUV); + vRoad0 = unpackOverlayLayer(aPacked2.x, aPacked2.y, rotRd0, baseUV); + vRoad1 = unpackOverlayLayer(aPacked2.z, aPacked2.w, rotRd1, baseUV); + + gl_Position = uProjection * uView * vec4(aPos, 1.0); +}