819a2467fac65b5274ed3bac84500a225d23b837
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
687c34d123 |
perf: lot size is a ladder the camera climbs, not a constant
`DETAIL_LOT_METRES = 160` was one number for a board that stopped being looked at from one distance, and it was wrong at both ends of the range it is now looked at from. Measured with `scripts/cost-at.mjs` on the merged board against a 400,000-triangle cap: | pose | before | after | lot | | --- | --- | --- | --- | | Los Angeles, 13 km | **688,536** | 343,372 | 400 m | | Los Angeles, 12.5 km | **678,546** | 343,372 | 400 m | | Los Angeles, 11 km | **654,656** | 390,602 | 250 m | | Los Angeles, 9 km | **635,806** | 380,762 | 250 m | | **Los Angeles, 7.7 km** | **621,866** | **375,196** | 250 m | | Los Angeles, 2.5 km | **415,780** | 345,340 | 200 m | | Los Angeles, 0.9 km | 297,148 | 363,454 | 40 m | | San Francisco, 7.7 km | 222,286 | 300,782 | 80 m | | San Francisco, 2.5 km | 216,292 | 279,158 | 80 m | | San Francisco, 0.6 km | 200,114 | 347,830 | 40 m | | San Francisco, 400 km | 355,763 | 355,763 | — | | San Francisco, 45 km | 270,377 | 270,377 | — | **Six poses were over the cap and five of them had never been measured.** Only the 7.7 km one was on record; 2.5 km over Los Angeles was at 415,780, and the whole band from 9 km up to where `DETAIL_STANDOFF_M` switches the metros off at 13.3 km ran 635,806 to 688,536, because the frustum there holds essentially the entire Southland. None of them is over now. San Francisco goes the other way — 4.2x the buildings at the poses the complaint was about, and 15,613 at the closest one against 849. No cap moved. **Zero new draw calls, and that is a bound rather than a sample.** It is the same `InstancedMesh`, the same geometry and the same material; a district is built at 40, 80, 160, 200, 250 and 400 m, all six rungs live in the store, and the live buffers hold whichever one the board chose. Draws are unchanged to the digit at every pose above. A test asserts the mesh identity across four rung changes. The lever is a **lot count, not a lot size**, because a lot size is the wrong thing to hang on the camera: at the same 22.6 km of engine stand-off San Francisco has 1,987 lots in frustum and Los Angeles has 23,000, so any rule in metres of lot or kilometres of reach is a different bill in the two cities. The board packs the finest rung whose *visible* sum fits 19,000 lots, which is 400,000 minus the 184,000 to 205,000 triangles everything-but-the-city measured at across the whole band this runs in — flat to 10%, which is why there is no stand-off ramp and why the one that was here first came out. Costs, honestly. `createBlocks` goes 264 ms -> 1,236 ms and its store 4.7 MiB -> 18.9 MiB, because every rung is walked and kept; the live instance buffers get *smaller*, 59,166 -> 19,000, since the mesh no longer has to be able to draw a rung nothing can afford. A rung change pops — each rung is its own survey, not a subdivision — and cross-fading would cost the draw call this board does not have. Los Angeles at 7.7 km is visibly thinner than the 621,866-triangle version it replaces. `TODO.md`'s LA section is rewritten around what is left: no budget cell stands at any of these poses, which was the first item on it and still is. 1,723 tests. |
||
|
|
4ba9b08a1b |
fix: cull a district by where it stands, not by where its footprint is at sea level
Two independent reviewers found the same defect in `a2a04e0`, which is the only reason it is being fixed rather than shipped. `DetailRange.r` is `reach` from the lattice sweep: the half-diagonal of the district's lat/lng bounding box plus a lot. That is a **plan** radius, and it is a good one — measured over all 59,166 instances, every lot is inside its own district's `r` of the centre with metres to spare. It was then used as the radius of a sphere pinned at `y = 0`, which is a different claim, and one this board does not support: a lot's local y is the ground under it times `verticalExaggeration`, and that is 15 on the merged board. **39 of 97 district ranges had lots outside their own cull sphere**, the worst by 4.78 units — 9.2 km of scene height, in the San Gabriel foothills. Swept over 32,400 poses built the way `scene.ts` builds them, 61 dropped lots that project strictly inside the NDC cube. Hillside buildings vanishing while you look at them. So the range carries `y0`/`y1` — walked once per district at build, over lots that were just pushed — and the test is `Frustum.intersectsBox` instead of `intersectsSphere`. Same six plane tests, and exact for the volume being described rather than right in x/z and wrong in y. Measured, SF 2.5 km: 215,598 → 216,392 triangles. The fix *adds* 794, which is the shape of a correct answer here — it stops discarding geometry that was on screen. The whole-board pose is unchanged and draws are unchanged at 437. The doc comments that asserted the invariant this violated are rewritten rather than deleted; they were the part most likely to survive a fix and mislead. Also corrected there: the pack declares 99 detail districts but ten emit no lot and carry no range, so the quoted reach statistics are over 89, not 99 — the file and the hand-off report disagreed. `blocksDetail.test.ts` gains a peak board, because the existing fixture cannot express this: it exaggerates by 2 with a 200 m hill, so every district's height is a rounding error next to its plan radius and a y=0 volume contains it by accident. The new board is one small district on a 3,000 m peak at 15x — lots at y 36.09-39.28 on a 2.70-unit footprint. Verified to fail against the old volume and pass against the box, rather than assumed to. |
||
|
|
a2a04e09c1 |
perf: the city is packed against the frustum, not just against a reach
`createBlocks` returns one `InstancedMesh` for every anonymous building on the board and three culls per *object*, so its bounding sphere contains California and nothing about it is ever rejected. Standing 2.5 km over Los Angeles the merged board packed 48,081 detail lots and 2,839 base lots — **480,810 triangles of buildings alone against a 400,000 cap**, two thirds of them behind the camera or off the sides. No budget cell stands there, which is why nothing had measured it. It was a live breach. `DetailRange` now carries the district's `reach` — already computed to size the lattice sweep and thrown away — and a range is recorded for *every* district that emitted a lot, base ones included. A range is packed when it is within reach and its sphere is in frustum, which drops the base set at any close pose: it used to be a fixed prefix of the buffer and was therefore drawn wherever the camera stood. Measured at 2.5 km of stand-off, reach only against reach and frustum: San Francisco 3,546 detail + 2,839 base becomes 1,987 + 0; Los Angeles 48,081 + 2,839 becomes 15,067 + 0. **For zero extra draw calls** — this is the one place where culling is free, because `WebGLIndexedBufferRenderer` returns on `primcount === 0`, so a repack to nothing is cheaper than one draw and six chunk meshes would have cost five draws to buy the same 28,390 triangles. The pad is 2% of the stand-off rather than a distance, because it covers one frame of lag and a frame is a long way at 400 km and nothing at 2.5. Measured, a fixed 4 km pad packs 8,079 lots at 2.5 km over Los Angeles for nothing; 2% packs what no pad packs, and is worth 966 lots at 7.7 km. Two hazards that come with a moving packing, both handled: `count` starts at 0 rather than at `baseCount`, so `hasDetail` asks the store whether it exists instead of subtracting (the old expression would be negative); and `InstancedMesh.boundingSphere` is nulled on every repack, because `Frustum.intersectsObject` computes it once over whatever `count` held and never again — a sphere computed over San Francisco would have hidden Los Angeles for the rest of the session. `updateBlocksDetail` with no frustum behaves exactly as it did, which is what every board that is not the merged one gets, and what the one up-front call at scene build gets so the opening frame is not a district short. It does not fix the 110 km pose over Los Angeles, where all 42 in-reach districts genuinely are in frustum: closing that needs a coarser `DETAIL_LOT_METRES` at long stand-off, which is separate work. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |