API Reference · Lights

EnvironmentLight

Namespace: Ava3D

public sealed class EnvironmentLight

The light that comes from everywhere: the sky, the ground, the room.

A metallic-roughness renderer needs this to be honest. A metal has no diffuse response at all — it is only what it reflects — so with a single key light a metal sphere is a black ball with one hot spot on it. Something has to fill the rest of the reflection, and this is it.

There are two models here and one property chooses between them. Without EnvironmentLight.Texture the environment is a two-colour hemisphere, EnvironmentLight.SkyColor above and EnvironmentLight.GroundColor below, evaluated analytically from the reflection vector: no cubemap, no prefiltering, no assets, and identical arithmetic on all three backends. A mirror under it reflects a smooth gradient rather than a room, which is characterless and is not wrong — roughness still reads correctly, metals still look like metal, and the whole model still runs on a phone.

With EnvironmentLight.Texture it is image-based lighting, and a hull reflects the place it is in. See there for what that costs and what it needs.

Properties

MemberDescription
Vector3 GroundColor { get; set; }

Linear RGB seen by surfaces facing down. The default is dim warm ground bounce.

EnvironmentImage HdrTexture { get; set; }

Linear HDR environment, taking precedence over Texture. Null retains LDR or analytic lighting.

float Intensity { get; set; }

Overall multiplier, 0 to switch the environment off entirely. Clamped to 0..8.

static EnvironmentLight None { get; }

An environment that contributes nothing, for scenes that want the key light alone.

IList<EnvironmentProbe> Probes { get; }

Baked room probes. At most two valid probes are active, selected by priority then order. Extra or invalid probes are reported in material diagnostics. Invalidate the view after changing this collection.

int ReflectionResolution { get; set; }

Width of each filtered equirectangular band. 128 by default; rounded down to a power of two, 32..512. Used only with EnvironmentLight.HdrTexture or EnvironmentLight.Probes. Filtering is cached and runs on a worker; see EnvironmentLight.Prepare for having it ready before the first frame.

int ReflectionSamples { get; set; }

Deterministic GGX/diffuse integration samples per texel, clamped to 32..512. Default 128. Used only with EnvironmentLight.HdrTexture or EnvironmentLight.Probes.

float Rotation { get; set; }

How far to turn EnvironmentLight.Texture about the vertical axis, in radians. Positive turns the sky eastward; the geometry does not move.

Worth having rather than asking callers to regenerate the image: it is how the reflection is lined up with a key light that was placed independently, and it is the cheapest possible time-of-day effect. Turns EnvironmentLight.HdrTexture and EnvironmentLight.Texture alike; no effect without either.

Vector3 SkyColor { get; set; }

Linear RGB seen by surfaces facing up. The default is a cool overcast sky.

Texture Texture { get; set; }

An equirectangular image to light and reflect the scene with, or null for the two-colour hemisphere above.

This is the difference between a metal that reflects a gradient and one that reflects a place. A metal has no diffuse response at all — it is only what it reflects — so under the analytic hemisphere every metal surface in a scene is a smooth vertical ramp, correct and characterless. Given an image, a hull picks up the structure of the sky it is flying through, and moving it changes what it reflects.

The layout is latitude-longitude, the usual one: u runs once round the horizon, v runs from the top of the sky at 0 to straight down at 1. It is exactly the mapping Primitives.Sphere generates, so one image can be both the sky sphere a viewer sees and the environment that lights what is inside it — which is what makes the reflection agree with the backdrop instead of merely resembling it.

What happens to it. The image is prefiltered once, on the thread that owns the scene, into a set of progressively blurrier copies — one per step of roughness — and the shaders read whichever two a surface's roughness falls between. That is what makes a rough surface reflect a wide, soft cone and a polished one reflect the sky sharply, from one image and without a cubemap. The result is cached against this texture's identity, so setting the same image on twenty scenes filters it once and assigning a different one is what pays for it again.

What it costs. Under ten milliseconds, once, on the frame the image first appears — and almost independent of how large it is, because the filtering happens at a fixed working size and only the first read scales with the source. Generate the image before the control is on screen if that one frame matters. Sampling it costs three texture reads per lit pixel, and nothing at all on a scene that leaves this null.

Range. A Texture is eight bits per channel, so this is a low-dynamic-range environment: it cannot carry a sun ten thousand times brighter than the sky the way an HDR probe can. Put the sun in DirectionalLight, where it belongs, and let this carry the rest.

Methods

MemberDescription
static EnvironmentLight FromTexture(Texture texture, float intensity = 1.0f, float rotation = 0.0f)

An environment lit by an equirectangular image. See EnvironmentLight.Texture.

texture

The image, laid out as EnvironmentLight.Texture describes.

intensity

Overall multiplier, clamped to 0..8.

rotation

Radians about the vertical axis.

double Prepare()

Filters this environment and its probes now, on the calling thread, so the first frame that needs them draws with them. Returns how long that took in milliseconds; a second call finds everything cached and returns at once.

Not needed for correctness: a scene shown before its environment is filtered draws with the environment it had before — the plain sky and ground colours, the first time — and switches when the filter, which runs on a worker, lands. This is for the caller who wants the first frame lit by the image and is willing to wait for it; EnvironmentLight.PrepareAsync waits without blocking. Neither should be called while this environment or its probes are being changed.

Threading.Tasks.Task PrepareAsync(Threading.CancellationToken cancellationToken = default)

Filters this environment and its probes on the thread pool and completes when they are ready, so a scene shown afterwards draws lit by them on its first frame. See EnvironmentLight.Prepare.

cancellationToken

Stops the wait. The filter itself runs on and is kept, so the next frame that needs it still finds it.

static EnvironmentLight Studio(float brightness = 0.5f)

A neutral grey studio environment of the given brightness.

See also