Rendering and lighting
Vilanel's renderer uses forward shading, bindless resources and GPU-driven culling. Lighting uses real-world units, and rendering is tested with measurements and reference images.
How a frame is rendered
- Depth prepass and clustered forward shading. Lights are sorted into a 3D grid over the view, so each pixel only processes the lights near it. Forward shading also makes transparency and anti-aliasing simpler than a deferred renderer would.
- Reverse-Z floating-point depth, which keeps depth precision high at long distances.
- GPU-driven culling. Visibility, level of detail and skinning are handled on the GPU. The camera also uses occlusion culling based on the previous frame's depth, and each shadow is culled against its own view.
- Temporal anti-aliasing, with motion vectors that include skeletal animation so moving limbs do not smear.
Data shared by every camera, such as the sky, sky lighting and reflections, is computed once per frame. Data that belongs to one camera, such as culling, lights, shadows and history, is kept separately, so a second camera can render the same world in the same frame. Extra cameras are currently limited to previews, minimaps and probes.
Real-world light units
| Unit | |
|---|---|
| The sun | Lux (128,000 above the atmosphere) |
| Point and spot lights | Candela |
| Exposure | EV100, in photographic stops |
| Pixel brightness readout | Candela per square metre |
Real units make lighting predictable and measurable. After tonemapping, a surface that is far too bright can still look normal on screen, so the engine can report the physical brightness of any pixel to check it.
Exposure is based on how much light reaches the ground, so it adapts correctly at sunset. Automatic exposure is also available, but it is off by default so it does not override a level's intended look.
The sky
The atmosphere is recalculated every frame, so the sun can move freely. It is tested against a path-traced reference, and its settings are not tuned to match that reference, so the comparison stays meaningful.
Clouds are rendered as a 3D volume. They cast shadows on the ground and into fog, add light to the scene and appear in reflections. A level describes its weather as a schedule of presets, and the sky blends smoothly between them. A single wind moves both the clouds and the fog.
At night the sky shows real stars, a moon with phases that casts shadows, and a blue shift that mimics how our eyes adapt to the dark.
A level can also use a photographed HDR sky instead. Its brightness is set in real-world units, so it stays consistent with the rest of the lighting.
Testing
The runtime has options designed for testing:
| Option | What it does |
|---|---|
--screenshot | Render with a fixed clock, save a frame and exit |
--compare | Compare the frame with a stored reference image |
--camera | Set an exact camera position and angle |
--radiance | Print a pixel's brightness in real-world units |
--time, --weather | Set the time of day and the weather |
--gpu-timings, --cpu-timings | Show where frame time is spent on the GPU and CPU |
Reference images of the sample level are captured from fixed cameras, including one taken on the second frame to catch problems that only appear while the scene is loading. Two automated sweeps compare sky measurements across a whole day against stored values.
Related
- Scene and entities: where lights and cameras live
- Toolchain and projects: what the renderer is built with