writeSurface function

void writeSurface(
  1. FragmentContext c,
  2. Float32List v,
  3. ShaderBindings b,
  4. Vector3 normal,
  5. double roughness,
)

WriteSurfaceGeometry: the octahedral normal, the roughness, the depth.

Called from the same place that writes colour, so a surface cannot be lit into the frame without also describing itself — which is the failure that leaves a screen-space effect reflecting whatever was in the buffer before.

Metres along the view axis rather than coord.z, matching the GLSL: this rasteriser keeps its buffers in float32 and could store either, but the backends it is compared against cannot — a window depth in their half float stops distinguishing surfaces half a metre apart at twenty, which drew bands across the occlusion in every scene. Storing what the readers actually subtract costs nothing here and is the only version that survives the trip.

A debug pass takes the buffer over rather than getting one of its own, the way the GLSL does: the surface buffer already has an attachment, a viewer and a golden, and a second one would need all three built before it could answer anything.

Implementation

void writeSurface(
  FragmentContext c,
  Float32List v,
  ShaderBindings b,
  Vector3 normal,
  double roughness,
) {
  final depth = viewDepth(v, b);
  // A debug pass takes the buffer over rather than getting one of its own, as
  // `WriteSurfaceGeometry` does with `g_debug_surface_on`.
  final debug = c.debugSurface;
  if (debug != null) {
    c.surface = Vector4(debug.x, debug.y, debug.z, depth);
    return;
  }
  final encoded = encodeSurfaceNormal(normal);
  c.surface = Vector4(encoded.x, encoded.y, roughness.clamp(0.0, 1.0), depth);
}