Exclude deferred EnvCell subsets from the opaque turn, preserve exact CLIP/ALPHA fixed-state groups through leaf replay, and use retail's row-3 override, blend, depth, and texture-class alpha references. Keep the existing building-detail sentinel distinct from the two CLIP references.
Bound rejected source payload, replace no-op allocation proofs with actual EnvCell and particle RHI paths, rebuild checked-in SPIR-V, and correct AP-238/AP-240 plus the S4-c2 evidence record.
Gates: Release 0W/0E; hermetic 16735/0/0; InstalledDat 255 pass/10 known fail/1 skip; shaders 32/32; focused 239/239; allocation 2/2 at 0 B. The evidence/comment repair re-ran Release 0W/0E, shaders 32/32, affected 37/37, and allocation 2/2; mesh_detail.vert.spv remained byte-identical at SHA-256 5346247ab7d606046943e19b28888c814e08dc6cb27cd9750096ac055457eb57.
Mutation proof, with each mutation restored after its named first failure:
1. Restoring the opaque predicate to !IsAdditive fails WholeLeaf_MixedCellDrawsOpaqueAtTurnThenClipAndAlphaAtDrain first at draw count: expected 1, actual 3.
2. Selecting _alphaPipeline for CLIP fails WholeLeaf_ClipDrainBindsExactStateAndTextureClassReference first at the bind sequence: expected [envcell-clip], actual [envcell-alpha].
3. Disabling CLIP depth write fails that production Theory first at Assert.True(clipPipeline.Depth.Write): expected true, actual false.
4. Swapping palette/DDS references fails the DDS row first: expected 0.784313738, actual 0.392156869; the palette row reports the inverse.
5. Mutating mesh_modern.frag from < to <= fails ClipShaders_UseGreaterEqualForThePerRangeReference first at Assert.Contains("if (color.a < alphaCutoff) discard;"): the required source spelling is absent.
6. Restoring row-3 OverrideClipmap=true fails the real-interface clip Theory first at Assert.False: expected false, actual true.
7. Deleting failed-append rollback fails the flush/end/abort rejection-storm rows first at the bounded pending-count assertion: expected 0, actual 9000.
8. Selecting _transparentDetailPipeline for a ClipMap detail contribution fails the leaf detail pin first at the bind sequence: expected second bind envcell-retail-detail-clip, actual envcell-retail-detail-alpha.
9. Resetting detail ParamB to zero fails the same detail pin first at the second pushed reference: expected 0.784313738, actual 0.
10. Classifying CLIP with exact mask equality excludes legal 0x09 and fails WholeLeaf_PositiveStippleClipMaskUsesClipPipelineAndDdsReference first at pipeline: expected envcell-clip, actual envcell-alpha.
11. Mapping the new blend to SRC_ALPHA/INVSRCALPHA fails AllRetailBlendModesAreRepresentable first at the tuple: expected (One, OneMinusSrcAlpha), actual (SrcAlpha, OneMinusSrcAlpha).
12. Restoring mesh_detail.vert's uParamB > 0.5 category predicate fails ClipShaders_UseGreaterEqualForThePerRangeReference first because vDetailCategory = uParamB == 1.0 is absent.
13. Treating every positive detail uParamB as a cutoff fails that source pin first because isRetailClipReference(uParamB) ? uParamB : 0.05 is absent.
14. Adding arbitrary 0.5 as an accepted reference to either mesh_modern.frag or mesh_detail.frag fails that source pin first at Assert.DoesNotContain("value - 0.5"); both mutations were run and reversed independently.
Retail: D3DPolyRender::SetSurface @ 0x0059c4d0; paired binary @ 0x0059c72a, 0x0059c747/0x0059c74f, 0x0059c821, 0x0059c838, 0x0059c866.
104 lines
4.3 KiB
GLSL
104 lines
4.3 KiB
GLSL
#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;
|
|
}
|