Per-frame camera-motion re-sort scheduler (depth-sorting Phase 3, spec
§6). Registered as the 'depth-sort-scheduler' per-frame callback beside
'lod-group-selector'.
For each order-dependent node with a completed dispatch on record,
compare the live model-view z-row against the pose the last sort was
dispatched from and dispatch a re-sort when either
the view axis has rotated past config.depthSort.angleThresholdDeg
(relative to the node — a spinning node triggers it too), or
the camera has translated ALONG the view axis past
config.depthSort.translationFraction × the node's bounding-sphere
radius (which changes the behind-camera set the kernel clamps to the
far bucket).
Translation orthogonal to the view axis is deliberately ignored: the
kernel sorts by view-space z = axis·p + offset, so the permutation
cannot change unless the axis direction or the offset does.
Hysteresis is dispatch-updates-reference: scheduleSort records the
fresh pose, so a triggered node goes quiet until the camera moves past
the threshold AGAIN. Frames between dispatch and resolve render the
previous order — bounded staleness, standard 3DGS behavior. Skips:
pending view updates (the commit will sort anyway), in-flight sorts
(the resolve is at most a frame away), invisible/demoted meshes, and
nodes whose live mode is no longer order-dependent. A streaming
chunked apply does NOT skip — a fresher sort fills the inactive
buffer concurrently.
Work is tiered by dependency: frame-state cleanup runs above every gate,
pure main-thread cross-node ordering runs above the loader gate, and only
work that touches the SortWorker stays below that gate.
Per-frame camera-motion re-sort scheduler (depth-sorting Phase 3, spec §6). Registered as the 'depth-sort-scheduler' per-frame callback beside 'lod-group-selector'.
For each order-dependent node with a completed dispatch on record, compare the live model-view z-row against the pose the last sort was dispatched from and dispatch a re-sort when either
config.depthSort.angleThresholdDeg(relative to the node — a spinning node triggers it too), orconfig.depthSort.translationFraction× the node's bounding-sphere radius (which changes the behind-camera set the kernel clamps to the far bucket).Translation orthogonal to the view axis is deliberately ignored: the kernel sorts by view-space z = axis·p + offset, so the permutation cannot change unless the axis direction or the offset does.
Hysteresis is dispatch-updates-reference:
scheduleSortrecords the fresh pose, so a triggered node goes quiet until the camera moves past the threshold AGAIN. Frames between dispatch and resolve render the previous order — bounded staleness, standard 3DGS behavior. Skips: pending view updates (the commit will sort anyway), in-flight sorts (the resolve is at most a frame away), invisible/demoted meshes, and nodes whose live mode is no longer order-dependent. A streaming chunked apply does NOT skip — a fresher sort fills the inactive buffer concurrently.Work is tiered by dependency: frame-state cleanup runs above every gate, pure main-thread cross-node ordering runs above the loader gate, and only work that touches the SortWorker stays below that gate.