← The development journal

One environment, many effects

Why sky, sunlight, fog, and water need to agree about the world they are rendering.

A sky can look convincing in isolation and still disagree with the rest of a scene. The direct light might suggest a different sun. Fog might use different environmental inputs. Water can end up reflecting a version of the world that the other effects are no longer using.

In OmiLith, I have been treating atmosphere as shared lighting data rather than a sky-only effect. The goal is coherence between systems: several effects should be able to respond to the same authored environment, even when their rendering techniques and update costs differ.

Atmosphere data-flow diagram connecting transmittance, multiple-scattering and sky-view lookup tables to sky, sunlight, fog, clouds and water.
Shared GPU atmosphere lookup tables provide consistent inputs to sky, sunlight, fog, clouds, and water lighting. Open the full-size diagram.

Share the conditions

The renderer receives a shared environment sample carrying time, sun, wind, weather, and exposure. The game stays responsible for its clock and weather simulation. The rendering system consumes their result instead of trying to become a second simulation of the same world.

That division leaves a useful boundary. A game can decide what its environment means and how it changes. The renderer can decide how to represent those conditions on the selected device. Sky, direct sunlight, and fog then have a common set of inputs to work from.

It also makes a problem easier to locate. If two effects disagree, the question becomes whether they received the same environment, interpreted it consistently, and used the intended rendering path. There is a concrete handoff to inspect.

Reuse work when the inputs permit it

The full atmosphere route builds transmittance, multiple-scattering, and sky-view lookup tables on the GPU. Those tables turn parts of the atmosphere calculation into shared data that subsequent rendering can use.

Dirty keys control when the tables need updating. This makes the relationship between inputs and cached work explicit: reuse is useful while the inputs still describe the same calculation. When those inputs change, the relevant data needs to change with them.

A gradient or cubemap route remains available for devices where the full path is not the right tradeoff. The shared environment does not require every device to build the same tables or spend the same amount of GPU time. It gives the different paths a common description of the conditions they are trying to show.

Check the handoffs with an effect disabled

One bug in the water path exposed the value of testing combinations rather than isolated features. With atmosphere disabled, water used the environment sun instead of the authored scene light. The water could still render, but its lighting no longer followed the intended source.

The fix was in the handoff between systems. The journal records checks on both Mac and iPad after the change, including captures with atmosphere off. Disabling an effect made the remaining contract clearer: water still needed to use the appropriate light.

These cases are easy to miss when development concentrates on the full visual stack. A fallback path, or a deliberately disabled feature, can reveal an assumption that stays hidden when everything is enabled.

Coherence is larger than one shader

The same idea reaches beyond atmosphere. Water’s optical path depends on valid scene depth and colour inputs before using refraction. Fog needs a finite boundary at the visible surface. Temporal reconstruction needs to know when its stored history no longer matches the current view.

Each technique has its own mathematics, but the image also depends on the agreements between techniques. A renderer becomes easier to extend when those agreements are explicit.

For me, this is one of the most interesting parts of engine development. A new effect is not finished when it looks good on its own. It needs to participate in the same world as the effects already there, including on the simpler routes where some of the machinery is deliberately absent.

Have a thought or a question?
I'd love to hear it. ↗