mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-25 06:16:48 +00:00
ifcviewer: latch the motion contribution cull instead of flip-flopping
The coarse motion threshold (15 px vs the 3 px still floor) followed the per-frame "did the camera move" test directly. During a slow drag on a janky main thread — the 66-model web session at 20 fps, mouse events coalesced — some frames see no camera change, so the cull alternated between thresholds every few frames: 84% of the visible set vanishing and reappearing (139k <-> 22k objects in the log), with a full visible-set re-upload at each flip feeding the very jank that caused the gaps. On screen it read as the model sporadically jumping and returning while orbiting slowly, easing as streaming and caching settled — which is exactly how it was reported. The motion state now latches: any camera movement arms it, and it only drops after 250 ms of stillness, with the render loop kept alive over the hold so the fine-threshold re-cull actually runs in an on-demand loop. A drag degrades once at its start and restores once shortly after it ends. Measured with a deliberately gappy scripted drag: two transitions for the whole drag where each 120 ms pause previously flipped it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user