MIT License NuGet

Home / Docs / Render quality

Render quality

RenderQuality has two faces, and mixing them up is the most common early mistake with this engine. Static Default* fields are defaults you set before anything starts; RenderQuality.Current is the live instance you can write every frame.

The two faces

Initialization — static Default* fields, set in the app constructor. These bake shader variants and size allocations.

public App()
{
    RenderQuality.DefaultGlobalIllumination = GiMode.Ddgi;
    RenderQuality.DefaultAerialIntensity = 12f;
    RenderQuality.DefaultShadowAtlasSize = 4096;
}

RuntimeRenderQuality.Current, the live instance, safe to write from a settings screen or every frame.

var q = RenderQuality.Current;

q.HdrExposure = 1.2f;
q.ShadowDistance = 220f;
q.AoIntensity = 0.8f;
Every member says which one it is

Season/Rendering/RenderQuality.cs documents each member with a note on whether it is read once before graphics initialization or read every frame. Tier values — anything that decides a pipeline-state object, a render-target format or a buffer size — are locked before the frame loop starts and writing them later does nothing. Unsupported features are treated by a backend as an effective false rather than an error.

Where Current actually comes from

Current returns BaseApp.Settings.RenderQuality — the same object that is serialised into the settings file — falling back to a fresh instance when there is no app yet. BaseApp.Init() snapshots the Default* fields into it for new or empty settings.

Defaults do not reach an existing install

Because quality rides inside persisted settings, changing a Default* value affects a machine that has never run your application and no other. If you change a default and nothing happens on your development machine, that is why — delete the settings file, or set the value on Current as well. Anything you write to Current survives a restart, whether you meant it to or not.

The knobs worth knowing first

MemberDefaultRead
HdrSceneColortrueInitialization — decides the scene-colour format.
HdrExposure1.0Runtime.
AntiAliasingAaMode.TaaInitialization — also decides whether a post target exists at all.
AmbientOcclusionAoMode.GtaoInitialization.
AoRadius, AoIntensity0.5, 1.0Runtime.
GlobalIlluminationGiMode.OffInitialization — DDGI allocates probe and SDF volumes.
GiIntensity0.4Runtime.
BloomEnabledtrueInitialization; threshold, knee and intensity are runtime.
ShadowsEnabledtrueRuntime — off skips the pass.
ShadowAtlasSize2048Initialization.
ShadowDistance40Runtime.
SkySkyMode.ProceduralInitialization.
AerialIntensity1.0Runtime. See below.
TaaSharpness0.5Runtime; above zero buys an extra RCAS resolve pass.
KhrLightIntensityScale0.05Runtime — brings photometric glTF light values into engine range.
AnimatedBoundsScale1.5Runtime — how far skinned bounds are inflated for culling.
TextureMaxAnisotropy16Runtime; clamped to what the backend supports.

That is a selection, not the list. The file has roughly seventy members and each one carries its own note, which is a more reliable reference than any table on a website.

One knob explained properly

AerialIntensity is a good example of why the numbers in this API need their reasoning attached.

It is a lerp weight, not a multiplier

0 bypasses aerial perspective, 1 is the physical result, and above 1 extrapolates for emphasis. The engine default is 1. The reference application uses 12, because its world is only a few hundred metres across while real aerial perspective is a kilometre-scale effect — at 1 the distant mountains gain roughly two units of blue out of 255, which nobody can see. A kilometre-scale scene should move back towards 1 or 2, and a scene with no distance at all can turn it off.

Building a settings screen

The Settings panel in the reference application is the working example: it binds controls directly to RenderQuality.Current, writes on change, and lets the normal settings save carry the values to disk.

The one rule to encode in the UI is the split above. Runtime values can be sliders. Tier values need either a restart prompt or no control at all — a slider that silently does nothing until next launch is worse than an absent one.

WorldSettings has deliberately the same shape, for the same reason: static defaults, persisted instance properties, Current as the read. See Lighting and sky.