Luxar Viewer API Documentation - v2026.9.22
    Preparing search index...
    MESH_FRAGMENT_SHADER: string = ...

    Fragment stage.

    1. The derivative normal is computed unconditionally, before any guard-dependent branch. The epsilon guard below reads an interpolated varying, so branching on it is non-uniform control flow — where GLSL leaves dFdx/dFdy undefined, because normal validity can differ between fragments of the same 2×2 quad. Only the cheap gl_FrontFacing flip may sit behind the guard; never the derivative evaluation.
    2. The epsilon guard is written negated (!(dot(N, N) >= eps)), which is not a style choice: NaN fails every comparison, so a corrupt store's NaN normal fails >= and takes the fallback. The positive form dot(N, N) < eps would let it slip through and normalize into NaN shading.
    3. The two-sided flip applies to the stored normal only. gl_FrontFacing ? N : -N exists because double_sided defaults true and §5's whole-triangle cull exposes the interior back faces of a sliced closed isosurface: without the flip, the stored back normal shades on the wrong side of its gradient, producing an inverted result that can collapse toward uAmbient. The derivative normal needs no flip — cross(dFdx, dFdy) is defined by the rasterized fragment, not by the winding, so it always faces the viewer — and flipping it would reintroduce exactly that inverted shade, worst precisely at the degenerate vertices the guard is there to rescue. So the exemption is per FRAGMENT, not per variant.

    The three sibling types evaluate perspectiveNearFade per VERTEX (points/gsplats) or partly so (lines clip the segment in the vertex stage), because an instanced quad has one center depth and a per-vertex value is exact for the whole sprite. A triangle is not a sprite: it spans depth, so a per-vertex fade would interpolate the RAMP across the face and a large triangle straddling the fade band would render a linear smear instead of the smoothstep. Hence the fade is computed here, off the existing vViewPos varying.