Mesh shader family for the TSL ↔ GLSL parity harness: the six variants of
docs/specs/MESH_NODE_SPEC.md §6.4 — the opaque default (alpha cutout), the
alpha-weighted emission shared by additive/luminous/normal, the max
premultiply, the derivative flat-normal build, the colormap LUT build, and
mesh-pick.
What the pick entries can and cannot show
The harness renders to an UnsignedByteType target, so the pick pass's id
channels — nodeId in R and the two 16-bit halves in G/A — clamp and quantize to
8 bits. The pick entries therefore test what survives that: whether the two
backends discard the same fragments under the cutout, and whether they agree on
the brightness channel. The id SPLIT is pinned elsewhere, by construction rather
than by pixels — both backends route through one shared helper
(luxarElementIdSplit, single-sourced in glsl-lib.ts), the codegen snapshot
shows the TSL side's / 65536 and - hi * 65536, and a unit test round-trips the
split against voteWinner's recombination.
Five entries render under PERSPECTIVE
Every other entry uses the shared ORTHOGRAPHIC default camera, under which
perspectiveNearFade is the identity — so the near fade would ship with no
rendered parity coverage at all. mesh-near-fade, mesh-additive-near-fade and
mesh-pick-near-fade override buildCamera with the perspective
buildBehindCamera and pick a uNearCull that puts the whole quad at a partial
fade; the arithmetic is on NEAR_FADE_UNIFORMS below.
The two *-near-fade-reference entries render under the SAME perspective camera
with the fade made the identity (a uNearCull far inside the quad's depth), and
exist because the anti-vacuity
half of the parity test needs an un-faded frame of the same surface points. The
ortho default camera cannot supply one: its frame is 2.0 wide at z = 0 against the
perspective frame's 2·tan(30°) = 1.155, so pixel (i, j) is a different point on the
quad in the two framings and the "exactly 0.15625 ×" comparison would be measuring
that mismatch as well as the fade.
The fixture is a tilted-normal quad, on purpose
Two triangles in the z = 0 plane, but with per-corner normals fanned outward
(normalize(x·0.6, y·0.6, 1)). That is what makes the flat-vs-smooth pair a real
test rather than a tautology: the geometric normal of this quad is uniformly
+z, so a build that ignored shading and always shaded from derivatives would
render the flat and smooth variants IDENTICALLY. With fanned stored normals the
smooth variant carries a visible radial gradient and the flat one is uniform.
The colour attribute is float32 RGBA at four components, so vAlpha is a real
authored value (0.25 at one corner) rather than the constant 1.0 an RGB fixture
would supply — which is what gives the cutout and the max premultiply something
to act on.
Mesh shader family for the TSL ↔ GLSL parity harness: the six variants of
docs/specs/MESH_NODE_SPEC.md§6.4 — theopaquedefault (alpha cutout), the alpha-weighted emission shared byadditive/luminous/normal, themaxpremultiply, the derivative flat-normal build, the colormap LUT build, andmesh-pick.What the pick entries can and cannot show
The harness renders to an
UnsignedByteTypetarget, so the pick pass's id channels —nodeIdin R and the two 16-bit halves in G/A — clamp and quantize to 8 bits. The pick entries therefore test what survives that: whether the two backends discard the same fragments under the cutout, and whether they agree on thebrightnesschannel. The id SPLIT is pinned elsewhere, by construction rather than by pixels — both backends route through one shared helper (luxarElementIdSplit, single-sourced inglsl-lib.ts), the codegen snapshot shows the TSL side's/ 65536and- hi * 65536, and a unit test round-trips the split againstvoteWinner's recombination.Five entries render under PERSPECTIVE
Every other entry uses the shared ORTHOGRAPHIC default camera, under which
perspectiveNearFadeis the identity — so the near fade would ship with no rendered parity coverage at all.mesh-near-fade,mesh-additive-near-fadeandmesh-pick-near-fadeoverridebuildCamerawith the perspectivebuildBehindCameraand pick auNearCullthat puts the whole quad at a partial fade; the arithmetic is onNEAR_FADE_UNIFORMSbelow.The two
*-near-fade-referenceentries render under the SAME perspective camera with the fade made the identity (auNearCullfar inside the quad's depth), and exist because the anti-vacuity half of the parity test needs an un-faded frame of the same surface points. The ortho default camera cannot supply one: its frame is 2.0 wide at z = 0 against the perspective frame's 2·tan(30°) = 1.155, so pixel (i, j) is a different point on the quad in the two framings and the "exactly 0.15625 ×" comparison would be measuring that mismatch as well as the fade.The fixture is a tilted-normal quad, on purpose
Two triangles in the z = 0 plane, but with per-corner normals fanned outward (
normalize(x·0.6, y·0.6, 1)). That is what makes the flat-vs-smooth pair a real test rather than a tautology: the geometric normal of this quad is uniformly +z, so a build that ignoredshadingand always shaded from derivatives would render the flat and smooth variants IDENTICALLY. With fanned stored normals the smooth variant carries a visible radial gradient and the flat one is uniform.The colour attribute is
float32RGBA at four components, sovAlphais a real authored value (0.25 at one corner) rather than the constant 1.0 an RGB fixture would supply — which is what gives the cutout and the max premultiply something to act on.