feat(A.5 T20): MSAA 4x + alpha-to-coverage on foliage
Per Phase A.5 spec §4.9.2: ClipMap foliage uses binary alpha-cutoff. At N₂=12 horizon distance the pixel-stepped silhouettes are visible. A2C with MSAA 4x produces smooth retail-faithful tree edges. GL context now requests Samples=4. WbDrawDispatcher's opaque pass toggles GL_SAMPLE_ALPHA_TO_COVERAGE on/off around the multi-draw indirect call. mesh_modern.frag's opaque pass now discards only truly-empty (α<0.05) so the GPU derives sample mask from coverage; transparent pass boundary logic is unchanged. MSAA audit: no custom FBOs found — all rendering uses default framebuffer. Sky/particles/ImGui are all MSAA-compatible. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4b84e5650b
commit
26b2871b10
3 changed files with 10 additions and 1 deletions
|
|
@ -830,6 +830,7 @@ public sealed class GameWindow : IDisposable
|
||||||
ContextFlags.ForwardCompatible,
|
ContextFlags.ForwardCompatible,
|
||||||
new APIVersion(4, 3)),
|
new APIVersion(4, 3)),
|
||||||
VSync = false, // off during development so the perf overlay shows true framerate
|
VSync = false, // off during development so the perf overlay shows true framerate
|
||||||
|
Samples = 4, // A.5 T20: MSAA 4x for A2C foliage smoothing
|
||||||
};
|
};
|
||||||
|
|
||||||
_window = Window.Create(options);
|
_window = Window.Create(options);
|
||||||
|
|
|
||||||
|
|
@ -80,8 +80,11 @@ void main() {
|
||||||
vec4 color = texture(tex, vec3(vTexCoord, float(vTextureLayer)));
|
vec4 color = texture(tex, vec3(vTexCoord, float(vTextureLayer)));
|
||||||
|
|
||||||
// Two-pass alpha-test (N.5 Decision 2).
|
// Two-pass alpha-test (N.5 Decision 2).
|
||||||
|
// A.5 T20: opaque pass writes alpha as-sampled so GL_SAMPLE_ALPHA_TO_COVERAGE
|
||||||
|
// derives the MSAA sample mask from it — ClipMap foliage edges become smooth.
|
||||||
|
// Discard only fully-transparent (α < 0.05); the GPU handles coverage masking.
|
||||||
if (uRenderPass == 0) {
|
if (uRenderPass == 0) {
|
||||||
if (color.a < 0.95) discard; // opaque pass
|
if (color.a < 0.05) discard; // opaque pass — kill truly empty only (A2C)
|
||||||
} else {
|
} else {
|
||||||
if (color.a >= 0.95) discard; // transparent pass
|
if (color.a >= 0.95) discard; // transparent pass
|
||||||
if (color.a < 0.05) discard; // skip totally-empty
|
if (color.a < 0.05) discard; // skip totally-empty
|
||||||
|
|
|
||||||
|
|
@ -488,6 +488,10 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
|
||||||
{
|
{
|
||||||
_gl.Disable(EnableCap.Blend);
|
_gl.Disable(EnableCap.Blend);
|
||||||
_gl.DepthMask(true);
|
_gl.DepthMask(true);
|
||||||
|
// A.5 T20: enable A2C for ClipMap foliage — GPU derives sample mask
|
||||||
|
// from the alpha written by mesh_modern.frag so foliage edges are
|
||||||
|
// smooth under MSAA 4x. A no-op for fully-opaque (α=1) batches.
|
||||||
|
_gl.Enable(EnableCap.SampleAlphaToCoverage);
|
||||||
_shader.SetInt("uRenderPass", 0);
|
_shader.SetInt("uRenderPass", 0);
|
||||||
_gl.BindBuffer(BufferTargetARB.DrawIndirectBuffer, _indirectBuffer);
|
_gl.BindBuffer(BufferTargetARB.DrawIndirectBuffer, _indirectBuffer);
|
||||||
if (diag && _gpuQueriesInitialized) _gl.BeginQuery(QueryTarget.TimeElapsed, _gpuQueryOpaque);
|
if (diag && _gpuQueriesInitialized) _gl.BeginQuery(QueryTarget.TimeElapsed, _gpuQueryOpaque);
|
||||||
|
|
@ -498,6 +502,7 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
|
||||||
(uint)_opaqueDrawCount,
|
(uint)_opaqueDrawCount,
|
||||||
(uint)DrawCommandStride);
|
(uint)DrawCommandStride);
|
||||||
if (diag && _gpuQueriesInitialized) _gl.EndQuery(QueryTarget.TimeElapsed);
|
if (diag && _gpuQueriesInitialized) _gl.EndQuery(QueryTarget.TimeElapsed);
|
||||||
|
_gl.Disable(EnableCap.SampleAlphaToCoverage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Phase 8: transparent pass ────────────────────────────────────────
|
// ── Phase 8: transparent pass ────────────────────────────────────────
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue