nx_gsplat_density.nx
buildroot/runtime/nx_gsplat_density.nx
about
nx_gsplat_density.nx -- ADAPTIVE SPLAT DENSITY (split / clone / prune), rung 4 of the fitting ladder.
The fitter (gs_pos_grad_step_aniso) already measures, per primitive, everything this decision needs:
gradbuf[g*3], gradbuf[g*3+1] -- the screen-space residual gradient
gradbuf[g*3+2], wnorm[g] -- the Gauss-Newton curvature denominators
pa/pc[g] -- the conic, hence the screen footprint via gs_splat_rx/ry
depth[g] >= 0 -- visible in this view
So densification is a CLASSIFIER over state that already exists. It derives no new quantity and
re-renders nothing; a second measurement here would be a second ruler.
EVERY THRESHOLD IS DERIVED FROM THE POPULATION OR THE FORMAT. NONE IS PICKED.
The published 3DGS rule densifies on a view-space gradient above a FIXED tau (0.0002 in the paper).
That constant is calibrated to their units, their scene scale and their float pipeline; copying it
into an integer fixed-point renderer would be a picked number wearing a citation. So the bar here is
the population's OWN MEAN, recomputed every step:
DENSIFY iff |gx| + |gy| > mean(|gx| + |gy|) over VISIBLE primitives
A mean needs no parameter, adapts to scene scale and to fitting progress by construction, and cannot
go stale. L1 is used rather than L2 because this is an ORDERING against a mean of the same measure --
no square root, exact in integers, and monotone in the same direction as L2.
SPLIT vs CLONE, also against the population's own mean, and the reasoning is the paper's:
footprint > mean footprint -> SPLIT (over-reconstruction: one large splat spanning detail it
cannot represent; two smaller ones can)
footprint <= mean footprint -> CLONE (under-reconstruction: the region is under-covered, so add
a second primitive of the same size)
Footprint is the screen half-extent gs_splat_rx(ca) + gs_splat_ry(cc) -- the renderer's OWN support
radius, so a splat is judged by exactly the extent it actually paints.
PRUNE, derived from the FIXED-POINT FORMAT rather than from the population:
a splat contributes c*T*alpha/GFXA to a channel; peak over T<=GFXA and alpha<=op gives c*op/GFXA.
With the framebuffer quantised to 8 bits (c <= 255), that peak is below one quantisation step when
op * 255 < GFXA
Such a primitive CANNOT change any pixel at any depth or colour. It is invisible by the arithmetic
of the format, not by a judgement about smallness.
A view-dependent prune was CONSIDERED AND REJECTED, and the reason is multi-view correctness.
Pruning on zero accumulated footprint in this view, or on depth[g] < 0, would delete primitives that
are culled HERE and visible from another camera -- and the fitter is now multi-view (it cycles yaw
across steps). A prune rule that is correct per-view and wrong per-scene is the worst kind, because
every single-view test passes. Opacity is view-independent, so the shipped rule is.
dependencies 2 imports · 1 importers
imports: nx_syscalls.nxnx_gsplat.nx
imported by: nx_gsplat_density_gate.nx
structs
| none |
consts
| 55 | const GD_S_IN: i64 = 0 |
| 56 | const GD_S_KEPT: i64 = 1 |
| 57 | const GD_S_SPLIT: i64 = 2 |
| 58 | const GD_S_CLONED: i64 = 3 |
| 59 | const GD_S_PRUNED: i64 = 4 |
| 60 | const GD_S_OUT: i64 = 5 |
| 61 | const GD_S_GMEAN: i64 = 6 |
| 62 | const GD_S_RMEAN: i64 = 7 |
| 63 | const GD_S_VIS: i64 = 8 |
| 64 | const GD_S_REFUSED: i64 = 9 |
| 71 | const GD_S_ABOVEBAR: i64 = 10 |
| 72 | const GD_STATN: i64 = 11 |
| 74 | const GD_C_PRUNE: i64 = 0 |
| 75 | const GD_C_KEEP: i64 = 1 |
| 76 | const GD_C_SPLIT: i64 = 2 |
| 77 | const GD_C_CLONE: i64 = 3 |
functions
| 79 | func gd_stat_count() -> i64 { return GD_STATN } called by 1: main |
| 80 | func gd_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v } |
| 84 | func gd_invisible(op: i64) -> i64 { if op * 255 < gs_fxa() { return 1 } return 0 } |
| 88 | func gd_means(ng: i64, depth: *i64, pa: *i64, pc: *i64, gradbuf: *i64, out2: *i64) -> i64 |
| 111 | func gd_classify(gauss: *i64, ng: i64, depth: *i64, pa: *i64, pc: *i64, gradbuf: *i64, gmean: i64, rmean: i64, stats: *i64) -> i64 |
| 139 | func gd_copy(src: *i64, si: i64, dst: *i64, di: i64, st: i64) -> i64 called by 1: gs_densify |
| 148 | func gs_densify(gauss: *i64, ng: i64, ngmax: i64, depth: *i64, pa: *i64, pc: *i64, gradbuf: *i64, outbuf: *i64, m2: *i64, stats: *i64) -> i64 |