Skip to content

Fix line anti-aliasing: edge smoothing, minimum quad width, opaque blending with depth test#505

Merged
chrxh merged 6 commits intodevelopfrom
copilot/fix-line-render-step-anti-aliasing
Mar 8, 2026
Merged

Fix line anti-aliasing: edge smoothing, minimum quad width, opaque blending with depth test#505
chrxh merged 6 commits intodevelopfrom
copilot/fix-line-render-step-anti-aliasing

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 7, 2026

Thin lines in _LineRenderStep partially disappear because the fragment shader always outputs alpha = 1.0 with no edge falloff, and sub-pixel quads vanish when zoom * 0.15 drops below one pixel.

Changes

  • LineGS.h: Compute core half-width (max(zoom * 0.15 * 0.5, 0.5)) clamped to a minimum of 0.5px for sub-pixel visibility, then add a 1px AA margin outside the core for smooth edge fadeout. Pass coreEdge (ratio of core to total width) and edgeDist ∈ [-1, 1] to the fragment shader. No alpha reduction for sub-pixel lines — they render at full brightness with clamped minimum width.
  • LineFS.h: Apply smoothstep(coreEdge, 1.0, abs(edgeDist)) so the core region stays at full brightness and only the AA margin fades. Uses gl_FragDepth = 1.0 for edge pixels so they don't occupy the depth buffer at normal depth, allowing the subsequent _TriangleRenderStep to overwrite dim line edges via GL_LESS. Core pixels keep gl_FragDepth = gl_FragCoord.z for proper occlusion.
  • RenderStep.cpp: Keep opaque blend (GL_ONE, GL_ZERO) with depth testing (GL_LESS), matching _TriangleRenderStep. This prevents flickering caused by additive blending where overlapping line quads accumulate colors inconsistently as draw order changes between frames.

Key geometry shader logic

float coreHalfWidth = max(zoom * 0.15 * 0.5, 0.5);
float aaMargin = 1.0;
float totalHalfWidth = coreHalfWidth + aaMargin;
float coreRatio = coreHalfWidth / totalHalfWidth;

Key fragment shader logic

float edgeAlpha = 1.0 - smoothstep(coreEdge, 1.0, abs(edgeDist));
if (edgeAlpha < 0.99) {
    gl_FragDepth = 1.0;   // edge pixels don't block triangles
} else {
    gl_FragDepth = gl_FragCoord.z;  // core pixels block normally
}
FragColor = vec4(fragColor * edgeAlpha, 1.0);

🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

…roper blending

- LineGS.h: Add edgeDist/lineAlpha varyings, enforce minimum 1px quad half-width
  with proportional alpha reduction for sub-pixel lines
- LineFS.h: Use smoothstep edge falloff and lineAlpha for smooth anti-aliased edges
- RenderStep.cpp: Change blend from GL_ONE/GL_ZERO to GL_SRC_ALPHA/GL_ONE

Co-authored-by: chrxh <73127001+chrxh@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix anti-aliasing issues in LineRenderStep Fix line anti-aliasing: edge smoothing, minimum quad width, proper blending Mar 7, 2026
Copilot finished work on behalf of chrxh March 7, 2026 17:45
@chrxh
Copy link
Copy Markdown
Owner

chrxh commented Mar 7, 2026

@copilot the lines seems now thinner (too thin) and are thus rendered to dark.

Instead of fading within the original line width (which made lines thinner
and darker), add a 1px AA margin outside the core. The core region stays
at full brightness while only the margin fades smoothly. Pass coreEdge
ratio to fragment shader for adaptive smoothstep threshold.

Co-authored-by: chrxh <73127001+chrxh@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 7, 2026

@copilot the lines seems now thinner (too thin) and are thus rendered to dark.

Fixed in 1a5287a. The previous approach faded the outer 50% of the line quad width, which made lines appear thinner and darker.

The new approach keeps the core line at its original width (zoom * 0.15 * 0.5) and full brightness, then adds a 1px AA margin outside the core for smooth edge fadeout. The fragment shader uses smoothstep(coreEdge, 1.0, abs(edgeDist)) where coreEdge = coreHalfWidth / totalHalfWidth, so the core region remains at full intensity and only the extra margin pixels fade smoothly to zero.

Copilot finished work on behalf of chrxh March 7, 2026 20:05
@chrxh
Copy link
Copy Markdown
Owner

chrxh commented Mar 7, 2026

@copilot it is much better. but there is still a flickering. maybe one needs a z buffer as in the _TriangleRenderStep.

Additive blending (GL_SRC_ALPHA, GL_ONE) caused flickering because
overlapping line quads accumulated colors, varying with draw order.
With opaque rendering (GL_ONE, GL_ZERO) + depth test, each pixel has
a clean depth-buffer winner. AA edge fade still works via fragColor*alpha.

Co-authored-by: chrxh <73127001+chrxh@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 7, 2026

@copilot it is much better. but there is still a flickering. maybe one needs a z buffer as in the _TriangleRenderStep.

Fixed in 50a30cf. Changed the blend mode from additive (GL_SRC_ALPHA, GL_ONE) to opaque (GL_ONE, GL_ZERO) with depth testing, matching _TriangleRenderStep. The flickering was caused by overlapping line quads additively accumulating colors — as draw order changed between frames, brightness varied. With opaque rendering + depth test, each pixel has a single clean depth-buffer winner. The AA edge fade still works because fragColor * alpha produces dimmer edge pixels that blend naturally against the dark background.

Copilot AI changed the title Fix line anti-aliasing: edge smoothing, minimum quad width, proper blending Fix line anti-aliasing: edge smoothing, minimum quad width, opaque blending with depth test Mar 7, 2026
Copilot finished work on behalf of chrxh March 7, 2026 20:28
@chrxh
Copy link
Copy Markdown
Owner

chrxh commented Mar 7, 2026

@copilot at low zoom levels the lines are much too dark.

Copilot stopped work on behalf of chrxh due to an error March 7, 2026 21:18
// Enable blending (opaque with depth test, matching _TriangleRenderStep)
glEnable(GL_BLEND);
glBlendFunc(/*GL_SRC_ALPHA*/ GL_ONE, /*GL_ONE*/ GL_ZERO);
glBlendFunc(GL_ONE, GL_ZERO);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot The problem here is that before the LineRenderStep, the TriangleRenderStep is executed. Then the lines overwrite the triangles at the edges. But the boundaries of the lines are darker rendered at low zoom level. Maybe other blending function is needed or the color calculation for the lines is not optimal.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 5c4a7b8. The fragment shader now uses gl_FragDepth = 1.0 for AA edge pixels so they don't occupy the depth buffer at normal depth. This allows the subsequent TriangleRenderStep to overwrite dim line edges via GL_LESS. Core line pixels keep gl_FragDepth = gl_FragCoord.z to maintain proper occlusion. The blending stays opaque (GL_ONE, GL_ZERO).

…FragDepth for AA edges

Co-authored-by: chrxh <73127001+chrxh@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 7, 2026

@copilot at low zoom levels the lines are much too dark.

Fixed in 5c4a7b8. Two root causes:

  1. Sub-pixel alpha reduction was too aggressive — at zoom=1, coreHalfWidth=0.075 produced alpha=0.15, making lines 85% darker. Removed the alpha reduction entirely; sub-pixel lines now clamp to 0.5px half-width at full brightness.

  2. Dark AA edge pixels blocked triangles via depth buffer — since lines draw first and triangles second with GL_LESS, dim edge pixels prevented triangles from overwriting. Now AA edge pixels write gl_FragDepth = 1.0 (far plane) so triangles at normal depth can overwrite them. Core pixels keep normal depth.

Copilot finished work on behalf of chrxh March 7, 2026 21:40
@chrxh chrxh marked this pull request as ready for review March 8, 2026 17:39
@chrxh chrxh merged commit 1b9939a into develop Mar 8, 2026
2 checks passed
@chrxh chrxh deleted the copilot/fix-line-render-step-anti-aliasing branch March 8, 2026 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants