aeronautic

Performance

What a frame costs, and how to measure it.

The CPU

About a quarter of a millisecond per aircraft per frame: the flight's state, both trails and the bounds. The capture and the wing's vortex lattice only run when the shape changes. updateAir rewrites the condensation table, so write it when the day changes, not every frame.

The GPU

Each pixel of the vapor's box marches, skipping clear air by the distance the field reports to each part. In clear air that distance is all a step works out: the deficits, the moisture's patches and the shading are only looked up once the march is inside something that can fog. A tip vortex's trail, the dearest part of the field, is only followed behind the trailing edge, and a surface whose tips are too weak to fog doesn't look its trails up at all.

Two things keep a frame's cost even:

  • Coverage. Past 15 % of the screen, the steps coarsen as the square root of the box's area on screen, up to three times. Up close, the features a step resolves are many pixels across anyway.
  • Detail. Smaller than 6 % of the screen's height, the moisture's patches, the dearest part of a sample, are dropped.

quality caps any one pixel: "low" (64 steps), "medium" (112), "high" (160, the default) or "ultra" (256), or { maxSteps }:

<WingVapor quality="medium" />

Self-shadowing costs three more looks at the field for every sample that fogs. effects={{ selfShadow: false }} saves them, at the cost of a thick cone's grey underside.

Measuring it

Measure GPU time, not FPS. Create the renderer with trackTimestamp: true and read renderer.resolveTimestampsAsync("render"), from the worst view (the camera inside the vapor cone) and the common one. A frame's timestamps can resolve a frame or more late, and are coarse, so add them up over a few seconds and divide by the frames drawn (renderer.info.frame), or take a trimmed mean, rather than reading one frame at a time.

On this page