diff --git a/src/ifcviewer/ViewportCore.cpp b/src/ifcviewer/ViewportCore.cpp index f1f1c048e4..32cdf80268 100644 --- a/src/ifcviewer/ViewportCore.cpp +++ b/src/ifcviewer/ViewportCore.cpp @@ -7870,8 +7870,20 @@ void ViewportCore::render() { || camera_distance_ != prev_camera_distance_ || camera_yaw_deg_ != prev_camera_yaw_deg_ || camera_pitch_deg_ != prev_camera_pitch_deg_); + if (camera_moved) { + motion_cull_latched_ = true; + motion_hold_timer_.start(); + } else if (motion_cull_latched_ + && motion_hold_timer_.elapsed() >= kMotionHoldMs) { + motion_cull_latched_ = false; + } + // While the latch holds with the camera still, keep frames coming so + // the expiry actually happens and the fine-threshold re-cull runs — + // the loop is on demand, and a fully-resident scene would otherwise + // stay coarsely culled until the next input. + if (motion_cull_latched_ && !camera_moved) host_->requestFrame(); const bool use_motion_threshold = - camera_moved && motion_min_pixel_radius_ > min_pixel_radius_; + motion_cull_latched_ && motion_min_pixel_radius_ > min_pixel_radius_; const float effective_min_px = use_motion_threshold ? motion_min_pixel_radius_ : min_pixel_radius_; last_cull_was_motion_ = use_motion_threshold; diff --git a/src/ifcviewer/ViewportCore.h b/src/ifcviewer/ViewportCore.h index 7bf2846256..86d86a3be1 100644 --- a/src/ifcviewer/ViewportCore.h +++ b/src/ifcviewer/ViewportCore.h @@ -1632,6 +1632,19 @@ private: double last_cull_compute_ms_ = 0.0; double last_cull_upload_ms_ = 0.0; double last_stream_ms_ = 0.0; + // Motion-cull latch. The coarse motion threshold used to follow the + // per-frame "did the camera move" test directly, which flip-flops + // during a slow low-fps drag: coalesced mouse events leave frames + // where the camera happens not to change, so the cull alternated + // between the 3 px and 15 px thresholds — most of the scene vanishing + // and reappearing every few frames, with a full visible-set re-upload + // at each flip. The latch holds the coarse threshold until the camera + // has been still for kMotionHoldMs, so a drag degrades once at its + // start and restores once, shortly after it ends. + static constexpr int kMotionHoldMs = 250; + bool motion_cull_latched_ = false; + Stopwatch motion_hold_timer_; + // True when the cull just used motion_min_pixel_radius_ — render() // schedules one more frame so the camera-now-stopped state recomputes // the cull at the still threshold and previously dropped sub-pixel