docs(performance): camera crash cause pinned to Cesium's centre-pixel zoom; detection cost re-measured

Co-Authored-By: Claude Fable 5.2 <[email protected]>
This commit is contained in:
Mazeyar Moeini FeizabadiandClaude Fable 5.2 committed 2026-11-13 15:07:49 +01:00
1 parent 5aed9ce064
commit 22bdf14be1
1 file changed
+26 -14
+26 -14
View File
@@ -80,16 +80,21 @@ test, so place them on the ellipsoid with `HeightReference.NONE`.
### 3. Camera: rendering stops after pan then zoom ### 3. Camera: rendering stops after pan then zoom
Cesium's zoom-to-cursor path (`ScreenSpaceCameraController` `zoom3D` → Pure Cesium; no application code is involved. Above 1,000 km,
`handleZoom` → `Camera.rotate`) builds a rotation from a zero or NaN axis when `ScreenSpaceCameraController` `handleZoom` rotates the camera about the cross
the camera looks straight down at a whole-globe view, throws product of the picked point's normal and the screen centre's normal whenever
`DeveloperError: normalized result is not a number`, and Cesium stops its render their dot product is between 0 and 1. With the pointer on the exact centre pixel
loop for good. the two are the same vector, yet `n · n` often rounds to `0.9999999999999999`,
so the check passes with a zero axis. `Camera.rotate` then throws
`DeveloperError: normalized result is not a number` from
`Scene.initializeFrame`, outside the scene's own try/catch, so
`scene.renderError` never fires and Cesium stops its render loop for good. The
pans in the first reproduction only moved the camera to a pose where the
rounding goes that way.
Fix: keep the wheel zoom off the degenerate case (no zoom-to-cursor at near Fix: make `camera.rotate` ignore a zero or non-finite axis, and recover from any
−90° pitch above a set altitude, or a pitch nudged off exactly −90°), and handle stopped loop by restoring the last drawn camera pose and restarting it a bounded
`scene.renderError` by restoring a sane camera and restarting the loop, so one number of times before showing Cesium's error panel.
bad frame does not need a reload.
### 4. Street Traffic road loading ### 4. Street Traffic road loading
@@ -168,11 +173,18 @@ Two costs that scale with the 7,500 aircraft of a full poll:
- The detection overlay (`src/data/detection.js` `_drawOverlay`) collects every - The detection overlay (`src/data/detection.js` `_drawOverlay`) collects every
detectable object and strokes every bracket on every frame. detectable object and strokes every bracket on every frame.
Fix: skip the floor path for a contact clearly above any terrain, keep the floor Fix for the first: skip the floor path for a contact clearly above any terrain,
per aircraft per fix, make the floor-cell key a number, and stop promoting the make the floor-cell key a number, and stop promoting the cache entry on every
cache entry on every read. Collect detection candidates when the fleet pass, the read.
poll or the camera changes rather than per frame, and stroke the brackets as one
path per colour. The second turned out smaller than it looked. The bracket strokes are already
one path per colour, and collecting the objects is about 3 ms of a 56 ms frame
at 4x throttle once the first fix is in. What costs is the per-object loop in
`_drawOverlay` (projection, occlusion, alpha, twelve path calls per bracket),
about 13 ms per frame at 4x. Removing it means keeping the bracket paths across
frames while the camera and every contributing layer are unchanged, which needs
a revision signal from each detectable layer: a design change, left as a
follow-up.
### 9. Radio ### 9. Radio