#version 430 core #extension GL_ARB_shader_draw_parameters : require layout(location = 0) in vec3 aPosition; layout(location = 1) in vec3 aNormal; layout(location = 2) in vec2 aTexCoord; struct InstanceData { mat4 transform; }; struct BatchData { uint textureIndex; uint _pad; uint textureLayer; uint flags; }; layout(std430, binding = 0) readonly buffer InstanceBuffer { InstanceData Instances[]; }; layout(std430, binding = 1) readonly buffer BatchBuffer { BatchData Batches[]; }; // S3 review fix round 1 (F5): the per-cell screen-space gl_ClipDistance gate // (Phase U.3's binding=2 CellClip region SSBO) is deleted — the CPU-side // routing that could ever select a non-zero slot for an instance // (WbDrawDispatcher's per-frame clip-routing arming call) had ZERO production callers, so every // instance has always mapped to slot 0 (no-clip) in every shipped build; a // shader-side clip test against a table that only ever holds the reserved // no-clip slot clips nothing. binding=3 — PER-RENDERER per-instance slot // index, parallel to the binding=0 instance buffer and indexed by the // IDENTICAL per-instance index — stays declared (the CPU side still writes // it, always 0) but is no longer read here; the instance-buffer layout it // occupies is S5's to revisit. layout(std430, binding = 3) readonly buffer ClipSlotBuf { uint instanceClipSlot[]; }; // Exact uParamB=1 selects this per-instance building/object category. EnvCell // zero and its pure-ClipMap 100/255 or 200/255 references retain the bound // environment category; the fragment shader consumes those CLIP references. layout(std430, binding = 9) readonly buffer InstanceDetailCategoryBuf { uint instanceDetailCategory[]; }; // #188 per-instance opacity multiplier, identical binding and indexing to // mesh_modern.vert's InstanceAlphaBuf (binding 7). VM2's cdb read proved // retail's built-mesh detail combine is a single-pass texture-stage blend // whose stage-0 alpha is PREMODULATE(DIFFUSE, DIFFUSE) = diffuse.a * // detail.a (D3DPolyRender::SetSurface 0x0059c4d0) — the base subset's own // diffuse alpha gates how much detail shows through, exactly like the base // pass's translucency-fade multiplier already does for mesh_modern. 1.0 for // every opaque subset; <1.0 while a TransparentPartHook fade is in flight. layout(std430, binding = 7) readonly buffer InstanceAlphaBuf { float instanceAlpha[]; }; uniform mat4 uViewProjection; uniform int uDrawIDOffset; uniform uint uTextureIndexB; // absolute transform prefix in the shared pose arena uniform float uParamA; // detail UV tiling // Exact 1 remains the existing "require building instance" sentinel. S4-c2 // also passes 100/255 or 200/255 for an EnvCell ClipMap alpha reference; both // must retain the EnvCell category rather than taking the building branch. uniform float uParamB; out vec2 vBaseUv; out vec2 vDetailUv; out float vDetailOpacity; out vec3 vWorldPos; // review fix: mesh_detail.frag needs this for applyFog, // exactly like mesh_modern.vert's vWorldPos. out flat uint vBaseTextureIndex; out flat uint vBaseTextureLayer; out flat uint vBatchFlags; out flat uint vDetailCategory; void main() { int transformIndex = gl_BaseInstanceARB + gl_InstanceID; int instanceIndex = transformIndex - int(uTextureIndexB); vec4 worldPos = Instances[transformIndex].transform * vec4(aPosition, 1.0); gl_Position = uViewProjection * worldPos; vWorldPos = worldPos.xyz; // No distance term: VM2 found the fade only exists in // D3DPolyRender::DrawPolyInternal (0x0059d7c0, the immediate-polygon // path) and only when the static noFadeDetail (0x00820e38, initialised // to 1) is 0. Every loaded CGfxObj sets use_built_mesh=1 // (CGfxObj::InitLoad 0x005346b0), so buildings/EnvCells never reach that // function; their attenuation is the LINEAR mip chain converging to the // texture mean, which the existing sampler already provides. vDetailOpacity = instanceAlpha[instanceIndex]; vBaseUv = aTexCoord; vDetailUv = aTexCoord * uParamA; BatchData batch = Batches[uDrawIDOffset + gl_DrawIDARB]; vBaseTextureIndex = batch.textureIndex; vBaseTextureLayer = batch.textureLayer; vBatchFlags = batch.flags; vDetailCategory = uParamB == 1.0 ? instanceDetailCategory[instanceIndex] : 1u; }