Builtin Library
README.md
countingView module
Builds a camera view that counts, per pixel, how many fragments satisfy a depth
predicate, and colours the count. overdraw and zfighting are both instances
of it; a diagnostic of your own is one more.
local CountingView = require("@builtin::systems.renderDiagnostics.countingView")
return CountingView.new({
view = "myView", -- the name `capture pass=myView` selects
geometry = "@geometry.all", -- which drawables are counted
depthCompare = "always", -- which of their fragments count
levels = 16, -- counts that fit before the sum saturates
mapShader = asset.resolve("~.shaders.myViewMap", "shader"),
})
The return value is a .renderFeature module — render enqueues the view's
passes, teardown releases them — so a feature's whole init.luau is this one
call. Register the name separately with renderer.captureView.register so
capture pass=<name> resolves to it.
The two knobs that decide the question
depthCompare runs against the scene depth the frame already resolved:
"always"counts every fragment the rasterizer produced, hidden ones included — the shading work a pixel costs."lessEqual"counts only fragments reaching the winning depth — one per pixel, unless surfaces are close enough that the depth buffer cannot tell them apart.
geometry narrows what is counted: "@geometry.all", "@geometry.opaque" or
"@geometry.transparent".
Reading the count
levels is how many counts fit before the accumulated sum saturates at 1.0, so
a view's open-ended "this many or more" band belongs at or below that number.
mapShader is a @domain: post-process .shader asset declaring
fn zero_count_color(n: i32) -> vec3<f32> — the view's reading of the decoded
count, 0 where nothing was counted — over the shared decode body:
// @domain: post-process
fn zero_count_color(n: i32) -> vec3<f32> {
...
}
#include "~.shaders.countMap"
Flat, nameable bands read better from a still than a continuous ramp: the question is which band a region falls in, not how bright it is.