Paint a system's derived surfaces after entering it, not while building it
Every body with no photograph gets a surface derived from its measurements, a 128 by 64 texture painted on the main thread as its marker was built, inside the task that enters the system. At about 4.4 ms each (measured in node for the twenty the next commit adds, 88 ms together), that is the cost that grows with the number of bodies: with the solar system at 38 bodies, the long tasks after selectStar(0) were [219, 72], [228, 79] and [177, 72] ms over three runs, against [85, 72], [94, 75] and [78, 67] at 18. buildMarker now gives such a body its kind's flat colour and hands the painting to the renderer, which paints one surface per task (setTimeout 0) once the constructor has returned, and drops the rest if the system is left first. Measured in the running app (port 4311, three runs each, long tasks over 50 ms in the 9 s after entering the Sun's system): - 18 bodies: [79], [73], [77] ms. The task that entered the system is under 50 ms. - 38 bodies: [55, 72], [69, 78], [60, 83], and [52, 78] on a fourth run. The entering task is 52-69 ms, down from 78-94 before this change with 18 bodies, so the twenty new bodies add no long task over what the branch had. What they still add to it is not measured apart. The flat colour shows for a moment: the Sun's 29 derived surfaces were all painted 436, 689 and 399 ms after its renderer was built (three runs), and a surface once painted is cached, so a return visit paints them at once. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -453,6 +453,31 @@ describe('rotation', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('derived surfaces', () => {
|
||||
const maps = (renderer: SystemOrbitsRenderer): Array<THREE.Texture | null> =>
|
||||
renderer.members.map((member) => ((member.marker as THREE.Mesh).material as THREE.MeshStandardMaterial).map);
|
||||
const nextTask = (): Promise<void> => new Promise((resolve) => setTimeout(resolve, 0));
|
||||
const twoPlanets = (): SystemOrbitsRenderer =>
|
||||
new SystemOrbitsRenderer([], [exoplanet({ radiusEarth: 1.1 }), exoplanet({ id: 'TRAPPIST-1 c', name: 'TRAPPIST-1 c', radiusEarth: 1.0 })], undefined, 1);
|
||||
|
||||
it('paints them after the system is built, one a task, so entering a system is not held up', async () => {
|
||||
const renderer = twoPlanets();
|
||||
expect(maps(renderer)).toEqual([null, null]);
|
||||
await nextTask();
|
||||
expect(maps(renderer).filter(Boolean)).toHaveLength(1);
|
||||
await nextTask();
|
||||
expect(maps(renderer).every(Boolean)).toBe(true);
|
||||
renderer.dispose();
|
||||
});
|
||||
|
||||
it('paints nothing once the system is left', async () => {
|
||||
const renderer = twoPlanets();
|
||||
renderer.dispose();
|
||||
await nextTask();
|
||||
expect(maps(renderer)).toEqual([null, null]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('exoplanet size without a measured radius', () => {
|
||||
const radiusOf = (overrides: Partial<ExoplanetRecord>): number => {
|
||||
const renderer = new SystemOrbitsRenderer([], [exoplanet(overrides)], undefined, 1);
|
||||
|
||||
Reference in New Issue
Block a user