Phase 3A: screen-space contribution culling

Reject frustum-visible objects whose bounding sphere projects below a
pixel-radius threshold.  Applied at both BVH-node level (whole subtrees
pruned) and per-instance level; short-circuits when the camera is
inside the AABB so nothing-you're-standing-next-to is ever lost.
Pick pass passes threshold 0 so sub-pixel objects stay clickable.

Threshold defaults to 2 px (radius), overridable via IFC_MIN_PX env
var.  Measured on the 128 M-tri test scene (GTX 1650):

  0 px (off):   6.7 fps, 128 M tris
  2 px:        20.2 fps,  40 M tris (31%)
  4 px:        30.3 fps,  15 M tris (12%)

The metric is sphere-based (cheap: one sqrt per test) rather than
AABB-corner projection; loses a little precision on very elongated
bounds but costs ~5x less per test and the BVH-node pre-cull means
the long-tail-of-small-things case is already handled by subtree
pruning before we touch individual instances.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dion Moult
2026-04-13 09:51:09 +10:00
parent d3c21d7a81
commit 90366f8236
2 changed files with 69 additions and 5 deletions
+9 -1
View File
@@ -173,7 +173,13 @@ private:
// Frustum-cull m's instances (BVH if available, else linear scan),
// build the per-mesh DrawElementsIndirectCommand array + flat visible
// list, and upload both to m.indirect_buffer / m.visible_ssbo.
void cullAndUploadVisible(ModelGpuData& m, const float planes[6][4]);
//
// `min_pixel_radius` controls contribution culling: instances (and BVH
// subtrees) whose projected bounding-sphere radius would be below this
// many pixels are dropped. 0 = disabled (all frustum-visible kept),
// which is what the pick pass uses so clickable targets aren't filtered.
void cullAndUploadVisible(ModelGpuData& m, const float planes[6][4],
float focal_px, float min_pixel_radius);
// Mouse interaction
void handleMousePress(QMouseEvent* event);
@@ -224,9 +230,11 @@ private:
// Camera
QVector3D camera_target_{0, 0, 0};
QVector3D camera_eye_{0, 0, 0}; // world-space eye, set in updateCamera
float camera_distance_ = 50.0f;
float camera_yaw_ = 45.0f;
float camera_pitch_ = 30.0f;
float camera_fov_y_deg_ = 45.0f;
QMatrix4x4 view_matrix_;
QMatrix4x4 proj_matrix_;