Builtin Library
README.md
mediaTransmittance
Light attenuation through participating media, in a form both media and surfaces can sample.
A shadow map stores one depth per texel and answers a yes/no question, so nothing made of density can cast with it. This module owns the other representation: a light-space map holding the optical depth accumulated along each light ray, recorded at four points down its length.
Optical depth is additive. Every medium a ray crosses contributes to the same texel, so overlapping volumes stack with nothing to resolve between them. And because four points are stored rather than one total, a receiver standing halfway through a fog bank is attenuated by the half in front of it, not by the whole column.
Direct use
local Media = require("@builtin::systems.volumetrics.mediaTransmittance")
Media.set({ sunDirection = { 0.55, 0.55, 0.55 }, steps = 32 })
Media.setMedium("bank", {
position = { 0, 8, 0 },
size = { 20, 6, 20 },
density = 0.15,
})
Most scenes attach ParticipatingMedium to an entity instead and let it drive
this module.
API
| Call | Effect |
|---|---|
set(opts) | Scene-wide settings; omitted fields keep their value |
setMedium(key, opts) | Register or move a medium under a stable key |
removeMedium(key) | Drop one medium |
get() | A copy of the settings in force |
clear() | Drop everything and release the passes |
active() | Whether the passes are running |
Settings
| Field | Meaning |
|---|---|
sunDirection | Points toward the sun; light travels the other way |
strength | How much of the computed attenuation is applied, [0, 1] |
steps | Samples along each light ray, [4, 128] |
extent | Half-width of the map in world units; 0 sizes it to the media |
centre | Point the map is centred on; omit to centre it on the media |
Media
| Field | Meaning |
|---|---|
position | World-space centre |
shape | "box" (default) or "sphere" |
size | Half-extents, for a box |
radius | Radius, for a sphere |
density | Extinction per world unit |
Up to 32 media are packed into the records buffer.
Cost and limits
The map is 512×512 and is rebuilt each frame; steps sets the march length.
With nothing registered the passes are released entirely, so a scene with no
media pays nothing.
The map is sized to the bounding sphere of everything registered, so a small
bank sharing a scene with a much larger one lands on few texels — set extent
and centre explicitly to bias the map toward the region that matters.
Attenuation applies to surfaces. The sky keeps its own colour.