Depth and z-sort
Mesh and SDF shapes share a single depth texture in a single render pass. That is what makes them occlude each other correctly without an inter-pass copy.
The draws in pass 2
Section titled “The draws in pass 2”| Draw | Pipeline | Depth write | Depth compare |
|---|---|---|---|
| Fast SDFs | sdfFastPipeline | yes | less |
| Mesh | mesh.pipeline, or glassPipeline for a glass mesh | yes | less |
| Glass SDFs | sdfRefractPipeline | yes | less |
The <Fast> halo | sdfFastEffectPipeline | no | less |
| Effect SDFs | sdfPipeline | no | always |
The draw order
Section titled “The draw order”Fast SDFs → mesh → glass SDFs → the <Fast> halo → effect SDFs, then the rig
gizmo.
- Fast SDFs write depth. Dense clusters self-cull their own overdraw, and the depth they leave is what the mesh tests against.
- Mesh writes and tests. It is occluded by fast SDFs in front of it and occludes those behind it.
- Glass SDFs write and test like fast shapes. The image they refract is the background copy and the shape pre-pass, both made before pass 2.
- The
<Fast>halo tests against everything above and writes nothing. It comes after the glass so an outline in front of a glass shape paints over it; a band behind the glass fails against the glass depth and reaches the screen only through refraction, whenenableRefractionis on. - Effect SDFs draw last with no depth interaction. Their halo, glow and outline composite over everything before them.
The tradeoff
Section titled “The tradeoff”An effect SDF’s surface also always draws on top of the mesh, whatever its world position. A shape behind the mesh still appears in front of it.
This is why <Fast> shapes clip into a mesh and <Effect> shapes do not.
Fixing it needs the effect pipeline split into two: surfaces that write depth, halos that do not. That is designed and not built.
Effect shapes and the <Fast> halo do get a depth elsewhere, in the shape
pre-pass: sdfDepthOnlyPipeline draws the effect shapes, halo bands included,
and sdfFastEffectDepthPipeline draws the <Fast> halo at its shape’s closest
approach. Refraction uses that depth to reject what sits in front of the
glass, reflection to reject what sits behind it. The pass writes to its own
depth target and never reaches the main one, so it changes nothing about the
order above.
Why effects cannot simply write depth
Section titled “Why effects cannot simply write depth”A fragment shader has no per-fragment control over depth writing. The effect shader emits three kinds of pixel:
- Surface — the actual SDF surface. Should write depth.
- Halo and glow — colour beyond the silhouette. Must not write depth.
- Outline — near the surface, not on it. Must not write depth.
Turning on depthWriteEnabled writes depth for all three. The result:
- Halos erase geometry behind them. The halo claims depth at the surface position, so anything drawn later at greater depth fails its test across the whole halo region.
- Outlines go grainy. Sub-pixel raymarch variance gives neighbouring halo pixels slightly different depths, which then z-fight.
Both were observed. Do not enable depth writing on the effect pipeline without splitting the pass.