Sets the side of each cube face in texels, a power of two from 16 to 2048.
samples?
number= 64
Sets the samples per texel for rough reflections, from 1.
settings?
Partial<d.InferInput<typeof Settings>>= defaults, with intensity 1, rotation 0 and blur 0
Sets initial values over defaults.
StarsOptionsstars · 3 fields
cells?
number= 96
Sets the cells along each edge of a cube around the eye; each holds a star or none.
chance?
number= 0.2
Sets the share of cells that hold a star.
size?
number= 0.8
Sets the radius of a star's disc in pixels, at any resolution.
BackgroundOptionsbackground · 1 field
label?
string= 'environment background'
Labels its pipelines in GPU captures.
records
bake→encoder
build().draw→render
bake(encoder, source) when the source changes, before the passes that shade: one compute pass with a dispatch per mip level of both cubes and one for the harmonics.
owns
2 textures ·2 buffers ·a sampler ·5 pipelines and one per added function ·bind groups
The radiance and reflection cubes, the settings and the harmonics; the kernels that read a panorama, read a cube, halve the radiance, blur the reflections and sum the harmonics; a group per mip level and per added texture. Both cubes hold the mirror level, since a dispatch can't sample a texture it writes.
lifecycle
✓initAsync()✓destroy()✓[Symbol.dispose]
injects
definition
The cube, the harmonics and the settings that environment.reflection, irradiance, occluded, backdrop and ambient read.
binds
2 uniform
sky.ambient and the environment's functions, the settings and the harmonics, beside the reflection cube and a filtering sampler.
Drag to look round. Each sphere reads the reflections at its roughness, and the matte one the diffuse light. Move the time of day to re-bake the daylight; blur reads a rougher level behind the scene without a bake.
A lighting lights a surface from its sun and a two-colour sky. A real surface takes light from everywhere around it: a mirror shows the sky and the ground, brushed metal a blur of them, and a matte surface the sum of a whole hemisphere. Reading a panorama in every direction for every pixel is too slow for a frame, so an environment bakes it first. A bake turns the panorama into a cube of reflections at six roughnesses and nine numbers of diffuse light. Shading then reads one texel and sums nine terms.
Creates a sampled texture from one image. 8-bit images become rgba8unorm-srgb, or
rgba8unorm with color: 'linear'. Half-float images, and 8-bit ones with packed, become
format. Throws if the pixel count doesn't match the size, the image is empty or larger than
the device allows, packed comes with color, or format with 8-bit colour or data.
@param ― picture pixels from decode, decodeHdr or your own code, or a bitmap
@returns ― a texture you destroy, with every mip level unless mips is false
Decodes a Radiance .hdr file into linear half floats for an rgba16float texture. It reads
flat and run-length encoded RGBE scanlines in the standard -Y +X order, and clamps values
above 65 504, a half float's largest. It runs on any thread, a React Native worker included.
Throws for another orientation, an XYZE file, a side above 16 384 or a truncated or corrupt
file.
Creates an environment: a cube of radiance, a cube of reflections and nine spherical harmonics
of diffuse light, filled by bake from any source add prepared. Lit pipelines read it through
sky.ambient as the lighting's ambient hook; sky.background() draws it behind the scene.
Throws for a size that is not a power of two from 16 to 2048, or samples below 1.
@injects ― definition the cube, the harmonics and the settings that environment.reflection,
irradiance, occluded, backdrop and ambient read
@binds ― 2 uniform: sky.ambient and the environment's functions, the settings and the harmonics,
beside the reflection cube and a filtering sampler
@owns ― 2 textures, 2 buffers, a sampler, 5 pipelines and one per added function, bind groups: the
radiance and reflection cubes, the settings and the harmonics; the kernels that read a panorama,
read a cube, halve the radiance, blur the reflections and sum the harmonics; a group per mip
level and per added texture. Both cubes hold the mirror level, since a dispatch can't sample a
texture it writes
@records ― bake(encoder, source) when the source changes, before the passes that shade: one
compute pass with a dispatch per mip level of both cubes and one for the harmonics
@param ― options.size the side of each cube face, which sets memory and bake time
Makes a source ready to bake. A 2D texture is read as a panorama in equirectangular projection
and a 6-layer texture as a cube, each through a bind group; a function gets a kernel of its
own. Throws for other layer counts.
add(
constmeadow:images.Texture<[number,number]>
meadow);
await
constsky:environment.Environment
sky.
Environment.initAsync(): Promise<void>
Compiles the bake kernels and those of every added function.
Creates lighting with a sun, sky and fog. It can also read point lights from a table or a
function and cast shadows. Pipe its injection into each pipeline that uses it. Throws if
points names no source or more than one, a light function has neither count nor
candidates, a table comes with count, or candidates.ranges is anything other than a
positive integer.
@injects ― hook the shading hooks its options name: reflect, ambient, fog, sunShadow and
attenuation
@injects ― definition the sun, sky and fog, the shadows and the point lights, which shading
reads
@binds ― 1 uniform: shading.shade, the sun, sky and fog
@binds ― 2 storage, 1 uniform: shading.shade with a table of point lights
@binds ― 3 storage, 1 uniform: shading.shade with a table of lights whose positions are on the
device, the table's two parts
@binds ― 1 uniform: shading.shade with points.light or points.spot, plus what the function
binds
@binds ― 0 storage: shading.shade with points.candidates, plus what their functions bind, 2
storage for a neighbour grid's range and slot
@binds ― 1 uniform: shading.shade with a shadow, the sun's light space and cascades, beside the
depth array and its comparison sampler
@binds ― 1 uniform: shading.shade with pointShadow, each shadow's light, layers and views,
beside their depth array and the comparison sampler
@owns ― 1 to 3 buffers, a sampler, targets, a cameras.layered, passes: the sun, sky and fog; with a
shadow, its light space, the views of its cascades, a comparison sampler, the depth array and
the passes that draw it; with pointShadow, the same for the lights' faces
@records ― shadow.record and pointShadow.record with what was added to them, before the passes
that shade
@param ― options.shadow the sun's shadow, with a depth pass per cascade
@param ― options.pointShadow shadows that cast gives to lights of points.table, with a depth
pass per face
@param ― options.points point lights from a table or a 'use gpu' function. Every lit point visits
each slot up to the table's highest live one, or count with a function, unless candidates
names the slots that may reach it
Fills lighting's ambient hook with diffuse light and reflections from this environment:
lighting.create(root, { shading: { ambient: sky.ambient } }).
ambient}});
const
constscene:passes.Passes<{
readonly hdr:typeofpasses.color;
readonly depth:typeofpasses.depth;
}>
scene=
import passes
passes
.
functioncreate<{
readonly hdr:{
readonly format:"rgba16float";
};
readonly depth:{
readonly format:"depth24plus";
};
},{
readonly hdr:typeofpasses.color;
readonly depth:typeofpasses.depth;
}>(root:TgpuRoot,screen:targets.Targets<{
readonly hdr:{
readonly format:"rgba16float";
};
readonly depth:{
readonly format:"depth24plus";
};
}>,writes:{
readonly hdr:typeofpasses.color;
readonly depth:typeofpasses.depth;
},options?:passes.TargetOptions<{
readonly hdr:{
readonly format:"rgba16float";
};
readonly depth:{
readonly format:"depth24plus";
};
}>|undefined):passes.Passes<...>(+1overload)
Describes the targets and outputs for scene passes. With a surface such as the canvas, writes
only each renderer's colour. With a target set, writes colour into the target marked color,
depth into the target marked depth, and other outputs into their named targets. Multisampled
targets resolve according to resolve. Targets with layers draw one pass per layer, and every
target the description draws into needs the same layers. add builds a renderer's drawing.
begin starts a pass. pipe supplies fills such as a camera.
@param ― screen the surface, or the targets, which give the formats; each one the description
names is drawn into
@param ― writes what fills each target, by its key in screen
@returns ― a description you destroy, which holds the pipelines it builds
create(
constroot:TgpuRoot
root,
constscreen:targets.Targets<{
readonly hdr:{
readonly format:"rgba16float";
};
readonly depth:{
readonly format:"depth24plus";
};
}>
screen,{
hdr:typeofpasses.color
hdr:
import passes
passes.
constcolor:typeofpasses.color
Marks the target that receives each renderer's colour.
Adds fill after existing fills and returns a description of the same passes. Piped fills
take precedence over a drawing's own. For example, passes.create(…).pipe(view.inject()) uses
the camera from view.
pipe(
constview:cameras.OrbitCamera
view.
CameraBase.inject(): Inject
Fills cameras.current for the pipelines created from the configuration it is piped into.
Adds fill after existing fills and returns a description of the same passes. Piped fills
take precedence over a drawing's own. For example, passes.create(…).pipe(view.inject()) uses
the camera from view.
pipe(
constlight:lighting.Lighting
light.
Lighting.inject(): Inject
Fills the shading hooks and resources for pipelines created from the configuration you pipe
it into.
inject());
// After the opaque drawings: it fills only the pixels they leave
Builds a pipeline for drawing that writes every described output and returns its draw
methods. If the drawing cannot supply the fields an output needs, type checking fails with
that output's name. Use without to leave it out or instead to replace it.
Runs the loop on each scheduled frame. Time advances by at most maxDt per frame, never steps
back, and stops while the surface is paused. Destroying the animation keeps the loop alive.
Another animation on the same loop continues from its recorded time. A frame error stops the
animation.
@param ― loop the loop to run on each unpaused frame. Continues from its seconds if it ran before
@returns ― an animation you destroy to stop the frames
Records the bake of a source added to this environment into one compute pass of encoder.
Pipelines that read the environment see it in later passes.
bake(
frame:frames.Frame
frame.
Frame.encoder: TgpuCommandEncoder
Records commands for submission after the recorder returns. submit() replaces this encoder.
Read it at each call instead of keeping it, and let the frame submit it.
Begins a pass, draws drawn or each drawing in a list in order, then ends the pass. Reuse the
list to avoid allocating each frame. Call begin yourself when you need to choose drawings
per frame. Records nothing while enabled is false.
record(
frame:frames.Frame
frame,[
constbehind:passes.Drawn
behind]);// after the scene's opaque drawings
}),
);
sky.ambient is the lighting’s ambient hook. It replaces the sky gradient’s light with the environment’s diffuse light and reflections, at each material’s roughness. The sun still lights and shadows as before.
bake records one compute pass. Shading in later passes of the frame reads the new light.
add reads one of three sources and builds the kernel that bakes it. Add every source while loading, then bake the one to show:
A 2D texture is a panorama in equirectangular projection, such as a decoded .hdr file from images. It has +Y up, its centre facing +X and its left quarter facing −Z, as Blender writes it.
A texture of six layers is a cube map in WebGPU’s face order.
A 'use gpu' function from a direction to its light is a sky you write. Pipe its fills in, as tgpu.fn(f).pipe(light.inject()) does for one that reads the lighting.
A panorama needs one bake. Bake a function again when what it reads changes.
environment.gradient is the lighting’s sky gradient as a source: baked, it lights a matte surface as shading.hemisphere does while skyBottom is at least a fifth of skyTop, and adds reflections of the same colours.
environment.daylight is a sky from the lighting’s sun. It scatters sunlight through air and ozone, so the sky is blue by day, bright at the horizon and red at sunset. The lighting’s sky gradient adds to it at every hour and is all that remains once the sun sets. Keep skyTop and skyBottom at a night sky’s dark colours, or they tint the day:
Creates lighting with a sun, sky and fog. It can also read point lights from a table or a
function and cast shadows. Pipe its injection into each pipeline that uses it. Throws if
points names no source or more than one, a light function has neither count nor
candidates, a table comes with count, or candidates.ranges is anything other than a
positive integer.
@injects ― hook the shading hooks its options name: reflect, ambient, fog, sunShadow and
attenuation
@injects ― definition the sun, sky and fog, the shadows and the point lights, which shading
reads
@binds ― 1 uniform: shading.shade, the sun, sky and fog
@binds ― 2 storage, 1 uniform: shading.shade with a table of point lights
@binds ― 3 storage, 1 uniform: shading.shade with a table of lights whose positions are on the
device, the table's two parts
@binds ― 1 uniform: shading.shade with points.light or points.spot, plus what the function
binds
@binds ― 0 storage: shading.shade with points.candidates, plus what their functions bind, 2
storage for a neighbour grid's range and slot
@binds ― 1 uniform: shading.shade with a shadow, the sun's light space and cascades, beside the
depth array and its comparison sampler
@binds ― 1 uniform: shading.shade with pointShadow, each shadow's light, layers and views,
beside their depth array and the comparison sampler
@owns ― 1 to 3 buffers, a sampler, targets, a cameras.layered, passes: the sun, sky and fog; with a
shadow, its light space, the views of its cascades, a comparison sampler, the depth array and
the passes that draw it; with pointShadow, the same for the lights' faces
@records ― shadow.record and pointShadow.record with what was added to them, before the passes
that shade
@param ― options.shadow the sun's shadow, with a depth pass per cascade
@param ― options.pointShadow shadows that cast gives to lights of points.table, with a depth
pass per face
@param ― options.points point lights from a table or a 'use gpu' function. Every lit point visits
each slot up to the table's highest live one, or count with a function, unless candidates
names the slots that may reach it
Makes a source ready to bake. A 2D texture is read as a panorama in equirectangular projection
and a 6-layer texture as a cube, each through a bind group; a function gets a kernel of its
own. Throws for other layer counts.
Returns the light of a clear sky from Rayleigh and Mie scattering with ozone, lit by the
lighting's sun: sunDirection, and sunIntensity above the atmosphere. Below the horizon it
shows dark ground through haze. The lighting's sky gradient adds beneath, so it alone remains
at night. It draws no sun disc. Pipe light.inject() into it.
Returns a unit direction towards the sun at hour, from 0 to 24 in local solar time, at
latitude and with the sun's declination, both in radians: about 0.41 at midsummer in the
north, 0 at the equinoxes and −0.41 at midwinter. +X points east, +Y up and +Z south, so the sun
rises in +X and, north of the tropics, stands in +Z at noon. Turn the compass with
environment.turn. Below the horizon the direction points down. It runs on the CPU and in
shaders.
sunAt(
hour: number
hour,0.7,0.3);// 40° north in early summer
const
constcolor:d.v3f
color=
import environment
environment.
constsunColor:(direction:d.v3f)=>d.v3f
Returns the colour of sunlight at the ground with the sun in direction, for a sun of
intensity 1 above the atmosphere: white overhead, orange low and black below the horizon. Set
the lighting's sunColor to it with daylight. It runs on the CPU and in shaders.
sunColor(
constsun:d.v3f
sun);
constlight:lighting.Lighting
light.
Lighting.settings: TgpuUniform<d.WgslStruct<{
sunDirection:d.Vec3f;
sunIntensity:d.F32;
sunColor:d.Vec3f;
skyIntensity:d.F32;
skyTop:d.Vec3f;
fogDensity:d.F32;
skyBottom:d.Vec3f;
fogFalloff:d.F32;
fogColor:d.Vec3f;
skyReflection:d.F32;
fogStart:d.F32;
}>>
Holds the sun, sky and fog values from defaults and the settings option. Use patch to
upload only the fields you supply. The shadow's next record follows a sunDirection written
here.
Schedules work every every frames or hz times per second on average. Reports the time since
its last run. With hz, it runs in the frame closest to each scheduled tick. At 25 Hz and 60
fps, gaps alternate between two and three frames. Throws unless exactly one of every and hz
is set. every must be an integer above 0, and hz must be finite and above 0.
@returns ― a cadence whose due says whether the work runs this frame
cadence({
hz: number
Runs work hz times per second on average. Default none: set this or every.
hz:15});
const
constframe:(frame:Frame)=>void
frame=(
frame: Frame
frame:
(alias)interfaceFrame
importFrame
Represents one frame being recorded. Each run creates a separate object, so modules can
compare frames by identity.
Frame)=>{
if(
let moved:boolean
moved&&
constrebake:clock.Cadence
rebake.
Cadence.due(dt: number): boolean
Adds dt seconds and returns whether work is due this frame. Returns true on the first call.
due(
frame: Frame
frame.
Frame.dt: number
Reports seconds since the previous submitted frame. The first frame has a dt of zero.
Records the bake of a source added to this environment into one compute pass of encoder.
Pipelines that read the environment see it in later passes.
bake(
frame: Frame
frame.
Frame.encoder: TgpuCommandEncoder
Records commands for submission after the recorder returns. submit() replaces this encoder.
Read it at each call instead of keeping it, and let the frame submit it.
encoder,
constdaylight:environment.Prepared
daylight);
let moved:boolean
moved=false;
}
};
environment.sunAt(hour, latitude, declination) points to the sun at an hour of local solar time, with the latitude and the sun’s declination in radians: about 0.41 at midsummer in the north, 0 at the equinoxes. +X is east, +Y up and +Z south. Turn the compass with environment.turn.
sunIntensity is the sun above the air. environment.sunColor(direction) runs on the CPU and returns how much of it reaches the ground, reddened near the horizon and 0 below it. Set the lighting’s sunColor to it, so the sun lights surfaces as the sky shows it.
The sky’s brightness follows sunIntensity. The air dims a low sun far more than the sky around it, so expose for sunColor times sunIntensity.
Re-bake while the sun moves, at a capped rate as above.
environment.sunDisc(direction, brightness) returns the sun’s disc. Add it to a background of your own, below.
sky.settings holds intensity, rotation and blur. Shading reads them at every lookup, so changing one needs no bake.
intensity scales the diffuse light, the reflections and the background.
rotation turns the environment about the vertical, in radians, carrying +X towards +Z. Turn the lighting’s sun with it: environment.turn(direction, rotation) turns a direction the same way, on the CPU or the GPU.
blur is the roughness the background draws at, from 0 for the sharp panorama to 1.
Your own shaders read the environment through its functions. Fill them with sky.inject(). sky.ambient carries its own fills, so a lighting that takes it needs nothing more:
environment.reflection(direction, roughness) returns the reflection along direction at roughness.
environment.irradiance(normal) returns the diffuse light on a surface facing normal. A white matte surface under a uniform environment of radiance 1 gets 1.
environment.occluded(material, point, visibility) is the ambient light sky.ambient gives, darkened by a visibility from 0 to 1 on top of the material’s occlusion. Rough reflections dim as diffuse light does. Sharp ones dim less where the surface faces the eye and more at grazing angles. Give it ambient occlusion, recorded before the passes that shade:
Computes diffuse light and reflections from the environment, with visibility from 0 to 1,
such as ao.at(point.position), darkening both on top of the material's occlusion.
Reflections look along shading.reflectionOf, scaled by the lighting's skyReflection, and
both shares go through shading.surrounded, as shading.hemisphere's do.
occluded(
material:{
color: v3f;
roughness: number;
emission: v3f;
metallic: number;
occlusion: number;
}
material,
point:{
position: v3f;
normal: v3f;
view: v3f;
uv: v2f;
uv1: v2f;
}
point,
import ao
ao.
constat:(position:v3f)=>number
Returns the visibility of sky light at a world position, from 0 in a closed crease to 1 in the
open. It projects the position through cameras.current and blends the 4 nearest texels whose eye
distance matches. Where none matches, such as on a translucent surface in front of the opaque
one, it returns 1. Call it from shading in a pipeline piped with ao.inject(), such as an
ambient hook.
Creates lighting with a sun, sky and fog. It can also read point lights from a table or a
function and cast shadows. Pipe its injection into each pipeline that uses it. Throws if
points names no source or more than one, a light function has neither count nor
candidates, a table comes with count, or candidates.ranges is anything other than a
positive integer.
@injects ― hook the shading hooks its options name: reflect, ambient, fog, sunShadow and
attenuation
@injects ― definition the sun, sky and fog, the shadows and the point lights, which shading
reads
@binds ― 1 uniform: shading.shade, the sun, sky and fog
@binds ― 2 storage, 1 uniform: shading.shade with a table of point lights
@binds ― 3 storage, 1 uniform: shading.shade with a table of lights whose positions are on the
device, the table's two parts
@binds ― 1 uniform: shading.shade with points.light or points.spot, plus what the function
binds
@binds ― 0 storage: shading.shade with points.candidates, plus what their functions bind, 2
storage for a neighbour grid's range and slot
@binds ― 1 uniform: shading.shade with a shadow, the sun's light space and cascades, beside the
depth array and its comparison sampler
@binds ― 1 uniform: shading.shade with pointShadow, each shadow's light, layers and views,
beside their depth array and the comparison sampler
@owns ― 1 to 3 buffers, a sampler, targets, a cameras.layered, passes: the sun, sky and fog; with a
shadow, its light space, the views of its cascades, a comparison sampler, the depth array and
the passes that draw it; with pointShadow, the same for the lights' faces
@records ― shadow.record and pointShadow.record with what was added to them, before the passes
that shade
@param ― options.shadow the sun's shadow, with a depth pass per cascade
@param ― options.pointShadow shadows that cast gives to lights of points.table, with a depth
pass per face
@param ― options.points point lights from a table or a 'use gpu' function. Every lit point visits
each slot up to the table's highest live one, or count with a function, unless candidates
names the slots that may reach it
sky.background() is a drawing that fills every pixel left uncovered with the environment at blur, through the scene’s camera. It lies on the far plane and tests depth without writing it, so add it after the opaque drawings and before translucent ones. Covered pixels skip its shader.
It writes only colour. Every other output keeps its clear value, as where nothing drew, so TAA finds the sky’s motion from depth and the camera.
Depth must clear to 1, as it does by default.
{ label } names its pipelines in GPU captures.
For a background of your own, pass a 'use gpu' function from a direction to its light to environment.background, with its fills piped in. This one adds the sun’s disc to the daylight:
const
constwithSun:(direction:d.v3f)=>d.v3f
withSun=(
direction:d.v3f
direction:
import d
d.
export v3f
Interface representing its WGSL vector type counterpart: vec3f or vec3.
A vector with 3 elements of type f32
v3f)=>{
'use gpu';
return
import environment
environment.
constbackdrop:(direction:d.v3f)=>d.v3f
Returns the environment in direction at settings.blur, as sky.background() draws it.
Returns the sun's disc in direction, 0.5° across with a soft edge, at the lighting's sun
colour and intensity times brightness. Add it to a background's function. Pipe
light.inject() into it.
Makes a drawing that fills every pixel left uncovered with the light from its direction through
the scene's camera. It lies on the far plane and tests depth without writing it, so add it after
the opaque drawings, where early depth testing skips covered pixels, and before translucent ones.
It writes only colour: every other output, such as TAA's motion, keeps its clear value, as where
nothing drew. Depth must clear to 1, as it does by default. Pipe the function's fills in, such as
tgpu.fn(f).pipe(sky.inject()).
@param ― lightFrom a 'use gpu' function from a direction to its light, such as environment.backdrop
Applies a configuration transform to the slots and accessors this function reads,
as root.pipe does to a pipeline's.
pipe(
constlight:lighting.Lighting
light.
Lighting.inject(): Inject
Fills the shading hooks and resources for pipelines created from the configuration you pipe
it into.
inject()),{
BackgroundOptions.label?: string |undefined
Labels its pipelines in GPU captures. Default 'environment background'.
label:'sky',
});
environment.stars({ cells, chance, size }) returns a function that finds the star in a direction: at most one per cell of a cube around the eye, as a soft disc of radius size in pixels. It gives the disc’s coverage and three random values fixed per star, to shape its brightness, tint or twinkle. Call it only in a fragment shader, such as a background’s, since the disc reads derivatives:
Returns a 'use gpu' function that finds the star in a direction: at most one per cell of a cube
around the eye, with a Gaussian disc of radius size pixels wherever the direction is drawn.
Shape the light from its seed, as in tint * pow(star.seed.x, 6) * star.disc. Call it only in
a fragment shader, since the disc's size reads derivatives.
@returns ― a 'use gpu' function from a unit direction to the Star there
stars({
StarsOptions.cells?: number |undefined
Sets the cells along each edge of a cube around the eye; each holds a star or none. Default 96.
cells:96,
StarsOptions.chance?: number |undefined
Sets the share of cells that hold a star. Default 0.2.
Makes a drawing that fills every pixel left uncovered with the light from its direction through
the scene's camera. It lies on the far plane and tests depth without writing it, so add it after
the opaque drawings, where early depth testing skips covered pixels, and before translucent ones.
It writes only colour: every other output, such as TAA's motion, keeps its clear value, as where
nothing drew. Depth must clear to 1, as it does by default. Pipe the function's fills in, such as
tgpu.fn(f).pipe(sky.inject()).
@param ― lightFrom a 'use gpu' function from a direction to its light, such as environment.backdrop
A photographed sun is far brighter than its sky. Baked, it makes a mirror’s glint but no shadow, and its diffuse light rings: nine numbers can’t hold so small a source, so the side facing away from it darkens. environment.clip lowers the panorama’s brightest texels and returns the light it took from the strongest source, in the lighting’s units. Give that back as the lighting’s sun, with its shadow:
const{
constimage:images.HdrImage
Holds a copy of the panorama with no channel above the ceiling.
image,
constdirection:[number,number,number]
Points towards the source in the panorama's frame, before rotation.
direction,
constcolor:[number,number,number]
Holds the source's linear colour, with its largest channel 1.
color,
constintensity:number
Holds the source's light as the lighting's sunIntensity, 0 when nothing was clipped.
Lowers every channel of a panorama above ceiling to it, and returns the light it took from the
strongest source, such as a photographed sun, in the lighting's units. Give that back as the
lighting's sun: it then shadows, and the baked diffuse light doesn't ring. Clipped texels within
20° of a brighter one count as one source. It runs on the CPU, in time proportional to the
pixels. Throws for a ceiling outside 2^-14 to 65 504.
@param ― image a panorama in equirectangular projection, as environment.add reads it
@param ― ceiling the brightest a channel stays, in the panorama's linear units
@returns ― the clipped copy, and the strongest source's direction, colour and intensity
Makes a source ready to bake. A 2D texture is read as a panorama in equirectangular projection
and a 6-layer texture as a cube, each through a bind group; a function gets a kernel of its
own. Throws for other layer counts.
Creates a sampled texture from one image. 8-bit images become rgba8unorm-srgb, or
rgba8unorm with color: 'linear'. Half-float images, and 8-bit ones with packed, become
format. Throws if the pixel count doesn't match the size, the image is empty or larger than
the device allows, packed comes with color, or format with 8-bit colour or data.
@param ― picture pixels from decode, decodeHdr or your own code, or a bitmap
@returns ― a texture you destroy, with every mip level unless mips is false
create(
constroot:TgpuRoot
root,
constimage:images.HdrImage
Holds a copy of the panorama with no channel above the ceiling.
Creates lighting with a sun, sky and fog. It can also read point lights from a table or a
function and cast shadows. Pipe its injection into each pipeline that uses it. Throws if
points names no source or more than one, a light function has neither count nor
candidates, a table comes with count, or candidates.ranges is anything other than a
positive integer.
@injects ― hook the shading hooks its options name: reflect, ambient, fog, sunShadow and
attenuation
@injects ― definition the sun, sky and fog, the shadows and the point lights, which shading
reads
@binds ― 1 uniform: shading.shade, the sun, sky and fog
@binds ― 2 storage, 1 uniform: shading.shade with a table of point lights
@binds ― 3 storage, 1 uniform: shading.shade with a table of lights whose positions are on the
device, the table's two parts
@binds ― 1 uniform: shading.shade with points.light or points.spot, plus what the function
binds
@binds ― 0 storage: shading.shade with points.candidates, plus what their functions bind, 2
storage for a neighbour grid's range and slot
@binds ― 1 uniform: shading.shade with a shadow, the sun's light space and cascades, beside the
depth array and its comparison sampler
@binds ― 1 uniform: shading.shade with pointShadow, each shadow's light, layers and views,
beside their depth array and the comparison sampler
@owns ― 1 to 3 buffers, a sampler, targets, a cameras.layered, passes: the sun, sky and fog; with a
shadow, its light space, the views of its cascades, a comparison sampler, the depth array and
the passes that draw it; with pointShadow, the same for the lights' faces
@records ― shadow.record and pointShadow.record with what was added to them, before the passes
that shade
@param ― options.shadow the sun's shadow, with a depth pass per cascade
@param ― options.pointShadow shadows that cast gives to lights of points.table, with a depth
pass per face
@param ― options.points point lights from a table or a 'use gpu' function. Every lit point visits
each slot up to the table's highest live one, or count with a function, unless candidates
names the slots that may reach it
Fills lighting's ambient hook with diffuse light and reflections from this environment:
lighting.create(root, { shading: { ambient: sky.ambient } }).
ambient},
settings:{
readonly sunDirection:[number, number, number];
readonly sunColor:[number, number, number];
readonly sunIntensity: number;
}&((Partial<InferInput<WgslStruct<{
sunDirection:Vec3f;
sunIntensity:F32;
sunColor:Vec3f;
skyIntensity:F32;
skyTop:Vec3f;
fogDensity:F32;
skyBottom:Vec3f;
fogFalloff:F32;
fogColor:Vec3f;
skyReflection:F32;
fogStart:F32;
}>>>|undefined)&{
readonly sunDirection:[number, number, number];
readonly sunColor: [number, number, number];
readonly sunIntensity: number;
})
Sets initial sun, sky and fog values over defaults. Default defaults, which has no fog.
settings:{
sunDirection:[number, number, number]
sunDirection:
constdirection:[number,number,number]
Points towards the source in the panorama's frame, before rotation.
direction,
sunColor:[number, number, number]
sunColor:
constcolor:[number,number,number]
Holds the source's linear colour, with its largest channel 1.
color,
sunIntensity: number
sunIntensity:
constintensity:number
Holds the source's light as the lighting's sunIntensity, 0 when nothing was clipped.
intensity},
});
clip(image, ceiling) lowers every channel above ceiling, 30 by default, and takes what was above it. Clipped texels within 20° of a brighter one count as one source.
direction is in the panorama’s frame. Turn it with environment.turn(d.vec3f(...direction), rotation).
A panorama with two light sources of about equal light, such as two softboxes, gives back one of them. The other’s clipped light is lost.
sky.destroy() frees the settings, both cubes and the harmonics buffer. The textures you added stay yours. Functions that read the environment then throw The environment was destroyed. when a pipeline compiles.
A bake runs in one compute pass and can’t be split across frames. Re-bake a moving sky at a capped rate.
Reflections come from infinitely far away. They don’t move as a surface moves, and they don’t show the scene itself.
Nine numbers of diffuse light hold only broad changes. A small, bright source rings; clip it and light with the sun.
Each pipeline reads one environment. Two environments in one frame need two sets of pipelines.
Each environment holds two cubes of 8 bytes a texel with their mips: about 8 MB at size 256, four times that at each doubling, and 537 MB at 2048. A bake’s time grows with the texels too.
The reflection cube has six roughness levels from size 256. Below that it has fewer, so the roughest keeps 8 texels a side.