Dual-Depth Peeling for glTF Sorting Artifacts

Dual-depth peeling is an order-independent transparency (OIT) technique that eliminates visual sorting artifacts in complex glTF scenes by extracting both the nearest and furthest depth layers simultaneously in each render pass. By managing multiple render targets and performing depth comparisons directly within the fragment shader, graphics engines can accurately blend transparent surfaces without requiring CPU-side polygon sorting. This article explores how fragment shaders implement dual-depth peeling to resolve overlapping alpha-blended geometry in glTF models.

The Transparency Challenge in glTF

The glTF format uses an alpha-blending model where transparent surfaces rely on standard BLEND modes. When complex, concave, or self-intersecting meshes overlap, standard primitive-level or object-level sorting fails. Fragments are rendered out of order, leading to missing surfaces, halos, or inverted depth relationships. Because traditional depth buffering (Z-buffering) only retains the single closest fragment, it cannot natively handle multiple overlapping translucent layers without specialized techniques.

Dual-Depth Peeling Mechanics

Traditional depth peeling strips away one transparent layer per rendering pass from front to back. Dual-depth peeling halves the number of required geometry passes by peeling two layers concurrently: the outermost (minimum depth) and the innermost (maximum depth).

The algorithm requires an initialization pass followed by several iterative peeling passes:

  1. Initialization: Finds the global minimum and maximum depth bounds of the translucent glTF fragments.
  2. Peeling Passes: Discards fragments already captured in previous passes, discovers the next inner minimum and maximum depths, and accumulates the colors.
  3. Composition: Merges the front-accumulated and back-accumulated color targets onto the opaque background.

Fragment Shader Handling During Peeling

The core logic of dual-depth peeling resides in the fragment shaders used during the peeling passes. These shaders use Multiple Render Targets (MRT) and depth textures from previous passes to control fragment processing.

1. Depth Comparison and Discarding

In each peeling iteration, the fragment shader receives the depth boundaries resolved in the previous pass via depth/bounding textures (prevMinDepth, prevMaxDepth). The fragment shader samples its current screen-space depth using gl_FragCoord.z and applies boundary checks:

// Discard fragments outside the current working boundary
if (fragDepth <= prevMinDepth || fragDepth >= prevMaxDepth) {
    discard;
}

Any fragment falling outside these bounds has already been peeled and blended, ensuring that the shader only processes fragments that lie strictly between the previous layers.

2. Resolving New Min-Max Bounds

Using hardware blending equations or manual clamping, the shader writes to two depth channels (often mapped to an MRT setup such as vec2 or separate render targets):

  • A negative depth target (or min-blend target) to capture the closest remaining layer inside the boundaries.
  • A positive depth target (or max-blend target) to capture the furthest remaining layer inside the boundaries.

3. Color Accumulation

The fragment shader separates color processing into two blending schemes:

  • Front Layer (Under-blending): Fragments matching the newly resolved minimum depth are blended front-to-back into a front-color accumulator. Front-to-back blending maintains premultiplied alpha to ensure correct attenuation of underlying surfaces.
  • Back Layer (Over-blending): Fragments matching the newly resolved maximum depth are blended back-to-front into a back-color accumulator using standard over-blending equations.

Final Blending and Output

Once the desired number of peeling iterations is reached (typically 4 to 8 passes for typical glTF models), a final composite fragment shader merges the accumulated front colors, the back-blended colors, and the opaque background texture into the primary framebuffer.

By offloading depth evaluation to per-fragment operations within the shader, dual-depth peeling guarantees mathematically correct blending of transparent glTF surfaces regardless of geometry orientation, topology, or camera angle.