Builtin Library
README.md
volumetricSky
Orchestration backend for the VolumetricSky.component. Owns the
GPU resources the cloud layer needs (cloud volume, raymarch render
target, ping-pong TAA history pair, post-process composite) and
exposes a small public surface the component drives every frame.
Exports
M.spawn(opts?) -> id— spawn the singleton sky entity, or configure the one already standing, and return its id. Every weather parameter (coverage,sunDir,sunColor,sunIntensity,windSpeed, …) is settable at the top level or inside apresetsub-table; everyVolumetricSkycomponent field (shaderVariant,cloudSize,taaBlendAlpha, …) by its own name;namenames the entity. Parameters left out keep their current values. An option that names neither raises, listing both sets, and leaves no entity behind. A weather parameter takes the shape its default carries — a number, or an array of that many numbers — and a value of another shape raises naming the parameter.M.configure(opts) -> boolean— apply those same weather parameters and component fields to the sky already standing. Returnsfalsewhen none has been spawned.M.defaultPreset() -> table— a fresh copy of the weather configuration a sky spawned with no options carries. The copy is the caller's to edit.M.destroy() -> ()— release every resourcespawncreated.M.fillClouds(noiseParams) -> boolean: bake the cloud volume with the activecloud_noise_*shader when what it holds is not whatnoiseParamsdescribe, and return whether this call baked. A change to a shaping parameter, the colour, the seed, the size, the variant or the render device bakes at once, and a write to the noise shader'sshader.wgslorbindings.yamlbakes once the program it compiles is resident; a change to the wind alone bakes at mostnoiseParams.noiseRegenRatetimes per second (defaultM.DEFAULT_NOISE_REGEN_RATE,0= every call the wind moved) onnoiseParams.clock(defaultgetTime()).noiseParamsis the flat table produced byVolumetricSky.component'ssnapshotNoiseParams().M.volumeBakes() -> number: how many times the cloud volume has been baked since the module loaded.M.dispatchRaymarch(renderParams, viewport) -> ()— dispatch the activecloud_raymarch_*shader, blend with history via the TAA pass, and write into the composite target.renderParamsis the flat table fromsnapshotRenderParams().M.find() -> id?— return the id of the active VolumetricSky entity, ornilif none has been spawned byM.spawn.M.despawn() -> ()— despawn the entityM.spawnminted (does NOT free GPU resources — callM.destroy()for that).M.setCoverage(c) / M.setDensity(g) / M.setSun(dir, color, intensity?) / M.setWind(v)— convenience setters that route through the active component'spublicfields.M.reprojectionDepthNdc(camPos, fwd, aabbMin, aabbMax, near, far) -> number— the NDC z the TAA pass carries history through, taken from where the cloud stands along the centre view ray. A point at rangedtravelstranslation / dacross the screen, so this is what keeps a translating camera's history landing on the part of the picture the cloud moved to.
Usage
-- The component drives this module automatically. Direct M.* use is
-- rare; the canonical entry point is attaching VolumetricSky to an
-- entity (or loading a preset and passing it to component.add):
local sky = entity.spawn("sky")
sky.component.add("VolumetricSky", {})
-- Driving the layer by hand instead, a frame at a time. Each dispatch
-- creates the resources it needs at the size its own arguments name —
-- the cloud volume from `noiseParams.cloudSize / cloudHeight`, the
-- render target and composite from the viewport:
local Sky = require("@builtin::systems.volumetrics.volumetricSky")
Sky.fillClouds(noiseParams)
Sky.dispatchRaymarch(renderParams, { width = 1280, height = 720 })
Notes
shaderVariantselects which compute shader pair (cloud_noise_v3 + cloud_raymarch_v3/cloud_noise + cloud_raymarch_v4/cloud_noise_v5 + cloud_raymarch_v5). The module resolves the variant strings to absolute identities — relative paths don't work from a module body (the chunkname retains an.initsegment that throws off the rsplit-to-parent step inresolve_relative_dot).- The cloud volume + history pair are RGBA16F — 256×128×256 ≈ 32 MiB
VRAM. Drop to 192/96 via
cloudSize/cloudHeightif tight. - The TAA pass is a single compute dispatch blending current sample
with the previous frame's RT through the history pair. Set
taaBlendAlpha = 1.0to disable while still going through the same code path (useful for benchmarking). - All public setters write through to
VolumetricSky.component'spublicfields, which means they replicate as Sync if the component is sync-enabled. Tweaks survive scene reloads as long as the same entity is alive. SkyPresetand its defaults are declared here, and the component declares itspresetfield from them.M.spawn/M.configureread that same key set to tell a weather parameter from a component field, so a parameter added to the preset reaches the schema and the option routing in one edit.