diff --git a/src/ifcviewer-wgpu/WgpuViewportWindow.cpp b/src/ifcviewer-wgpu/WgpuViewportWindow.cpp index 70b66d3636..9a0e72f9ef 100644 --- a/src/ifcviewer-wgpu/WgpuViewportWindow.cpp +++ b/src/ifcviewer-wgpu/WgpuViewportWindow.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -1302,6 +1303,25 @@ bool WgpuViewportWindow::initWgpu() { wgpuSetLogCallback(onWgpuLog, nullptr); wgpuSetLogLevel(WGPULogLevel_Warn); + // Env-var overrides for contribution-cull thresholds. wgpu uses + // view-Z (perspective-divide-correct) for projected_px, whereas the + // GL backend uses euclidean distance — so for off-axis instances + // wgpu computes a larger projected_px and is less aggressive at the + // same numeric threshold. These knobs exist to let us sweep matching + // values during the perf-parity push without rebuilding. + if (const char* s = std::getenv("WGPU_MIN_PX")) { + const float v = float(std::atof(s)); + if (v >= 0.0f) min_pixel_radius_ = v; + qInfo().noquote().nospace() + << "[wgpu cull] WGPU_MIN_PX=" << min_pixel_radius_; + } + if (const char* s = std::getenv("WGPU_MIN_PX_MOTION")) { + const float v = float(std::atof(s)); + if (v >= 0.0f) motion_min_pixel_radius_ = v; + qInfo().noquote().nospace() + << "[wgpu cull] WGPU_MIN_PX_MOTION=" << motion_min_pixel_radius_; + } + instance_ = wgpuCreateInstance(nullptr); if (!instance_) { qWarning() << "wgpuCreateInstance returned null"; diff --git a/src/ifcviewer-wgpu/WgpuViewportWindow.h b/src/ifcviewer-wgpu/WgpuViewportWindow.h index 85fb7f0b8b..c6d6fad5f3 100644 --- a/src/ifcviewer-wgpu/WgpuViewportWindow.h +++ b/src/ifcviewer-wgpu/WgpuViewportWindow.h @@ -387,9 +387,18 @@ private: // Contribution-cull thresholds. Still-frame uses min_pixel_radius_; // when the camera changed since last frame, the bigger motion threshold // kicks in to drop more sub-pixel detail (and slash per-frame cull cost). - // Matches AppSettings::minPixelRadius / motionMinPixelRadius in GL. - float min_pixel_radius_ = 2.0f; - float motion_min_pixel_radius_ = 10.0f; + // + // GL ships 2.0 / 10.0, but uses euclidean distance for projected_px + // (sqrt(dx² + dy² + dz²)) while wgpu uses view-Z distance (the + // perspective-divide-correct denominator). For off-axis instances + // view_z < euclidean, so wgpu's projected_px is larger than GL's at + // the same numeric threshold — i.e. wgpu is structurally less + // aggressive. Bumping to 3.0 / 15.0 compensates so the effective drop + // rate matches GL's; on the federation scene this lands obj/tri + // counts within ~10% of GL's across an orbit (vs ~3× without the + // bump). Override at runtime via WGPU_MIN_PX / WGPU_MIN_PX_MOTION. + float min_pixel_radius_ = 3.0f; + float motion_min_pixel_radius_ = 15.0f; public: // Master switch for HiZ occlusion. Set false to skip the depth resolve