Raise the threshold to stop dimmer discs glowing, or reduce levels to narrow the glow. Each disc is twice as bright as the previous one.
Linear light can exceed 1. Blockfall’s cleared blocks flash brighter than white. Clipping to the screen range of 0 to 1 turns bright colours yellow, bands dark gradients and loses glow. Use finish.create for a final pass that maps the image to the screen with one full-screen triangle. Add bloom, FXAA, TAA or depth of field around it.
Creates render targets that follow a size. Replaces the whole set when the size changes. Put
targets needed only sometimes in their own set and create that set when needed. Throws for
transient targets with sampling, storage or mip levels, for multisampled targets with storage or
mip levels, and for layered targets that are multisampled, mipped or have more layers than the
device allows.
@param ― source the size it follows, such as a surface
@param ― specs a format and options per target, by name
@param ― options.resolution the fraction of each side drawn, which changes without allocating
@returns ― a set of targets you fit every frame and destroy
Creates bloom from a chain of half-size textures. Each level downsamples with 13 taps, then a
tent filter adds it to the next larger level. The result is mip 0 of output, at half the
source size. With region, passes draw and sample only that region; changing the region
allocates nothing.
@allocates ― on resize: a new chain and the bind groups of its passes; so does a new source
@owns ― targets, a sampler, 3 pipelines, 2 bind groups and a buffer per level: the chain of glow
levels, the settings, a group for each pass, and the region each pass reads
@records ― record after whatever wrote the source; then output holds the glow.
@param ― options.source the HDR picture, read at every record
@param ― options.region the part of the source that holds the picture, read at every record
@returns ― a bloom you record every frame and destroy
Provides the HDR picture: a rendered picture, such as aa, or a function returning a
texture, such as () => screen.textures.hdr. record reads it on every call, so the texture
can be rebuilt.
Creates the final pass of a frame. It reads the source, adds glow, tone maps, grades, applies
the vignette, encodes and dithers. It draws one triangle into the caller pass.
@allocates ― on resize: a bind group for a new source or glow
@owns ― 2 buffers, a sampler, a pipeline, 2 bind groups: the settings, the regions it reads, and a
group each for the source and the glow
@records ― record into a pass of its own on the view you give, usually the canvas's, or draw
into the caller's pass, after the bloom's record.
@param ― options.source the picture, rendered or a texture, read at every draw
@param ― options.region the part of the source that holds the picture, read at every draw
@param ― options.glow a bloom, or a glow of your own, added before tone mapping
@param ― options.exposure an adapted exposure, read on the GPU
@returns ― a final pass you draw every frame and destroy
create(
constroot:TgpuRoot
root,{
Options.format: GPUTextureFormat
Sets the output format, such as the canvas format.
Provides the picture at any size: a rendered picture, such as aa or blur, or a function
returning a texture, such as () => screen.textures.hdr. draw reads it on every call, so
the texture can be rebuilt.
source,
Options.glow?:finish.Rendered|undefined
Adds a bloom, or a glow of your own such as an emission target, before tone mapping. draw
reads its output and region on every call. Default none.
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
Rebuilds all textures if the source size changed, destroying the old textures. Updates
regions for the current resolution. Returns true after a rebuild so callers can update bind
groups that hold old textures. Call before recording passes that use the targets. Throws after
destroy.
fit();
const
constscene:TgpuRenderPass
scene=
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.
Opens a pass on view, such as surface.view(frame), draws into it and ends it. A
viewport draws the picture into that rectangle and clears the rest, transparent with
alpha: 'premultiplied' and black otherwise. Optional timer writes measure the pass.
record(
frame:frames.Frame
frame,
constsurface:web.Surface
surface.
Surface.view(frame: frames.Frame): GPUTextureView
Returns a view of the current canvas texture, created once per texture. Applies pending size
changes first, which a pass using context would skip.
view(
frame:frames.Frame
frame));
}),
);
final.record(frame, view) opens a pass on view, draws and ends it. It also takes an encoder in place of the frame. final.draw(pass) draws into a pass you opened, such as one a HUD draws into afterwards. record(frame, view, { timestampWrites }) times the pass under one profiler timer.
record(frame, view, { viewport }) draws the picture into a rectangle of the view, such as a letterbox, and clears the rest to black, or to transparent with alpha: 'premultiplied'.
The source is a function returning a single-sampled float target with sampled: true, or a picture another module rendered, such as aa, blur or glow. Other sources fail to type-check. A 32-bit float format requires float32-filterable. Each draw or record reads current source, region and texture values, so target resizing through fit() is supported.
A rendered picture brings its region. Give region yourself only with a function source drawn below full resolution, such as screen.regions.hdr.
The final pass adds glow to its own source. Bloom can therefore read a separate image, as in What glows. Any object with output, and optionally region, can supply glow.
Each pixel applies these stages in order: glow, exposure, tone, grade, vignette, sRGB encoding and dither.
Uniform values of zero do not remove shader work. Vignette, dither and glowIntensity still run their calculations, and glow still samples. Omit stages with no glow, tone: null, no grade or encode: false. Dither always runs.
Convert screen-picked sRGB colours once with srgbToLinear from @typegpu/color. It runs on the CPU too.
Falling sand renders to a small target and upscales it with filter: 'sharp'.
Raise exposure to see where each colour strip turns white. The plot shows grey light through each curve, and the strips show one colour at increasing brightness.
tone
tone.neutral (default)
Khronos PBR Neutral. Keeps hue until the highlights.
tone.aces
Narkowicz’s fit of ACES. Bright colours go white.
tone.reinhard
On luminance. Soft, and never reaches white.
tone.agx
Blender’s AgX. Bright colours fade to white evenly.
A wide full-resolution blur needs hundreds of samples per pixel. Bloom reduces that work by blurring progressively smaller levels.
Choose a small source to see the chain stop when its dimensions run out. Each pass draws one triangle.
On the way down, each level halves the dimensions and samples 13 taps. Jimenez’s filter combines five overlapping four-tap boxes, weighted one half for the centre and one eighth per corner.
The first downsample keeps bright values through bright. It uses a Karis average, weighting boxes by 1 / (1 + luminance), to prevent flicker from isolated bright pixels.
The default bright is bloom.threshold. It keeps the excess of the brightest channel above threshold. A quadratic softens the transition starting knee × threshold below it.
On the way up, each level samples the smaller level through a 3 × 3 tent, with weights 1, 2 and 4 divided by 16. Taps are spread texels apart. Add the filtered result to the next larger level.
Level 0 of the rgba16float output holds the final glow at half the source dimensions. The final pass multiplies it by glowIntensity before exposure and tone mapping.
A region restricts bloom to the source area drawn at lower resolution. Each level reads and draws its corresponding region. glow.region gives the glow’s region, which the final pass reads through glow.
record takes the frame or an encoder. record(frame, { timestampWrites }) times all its passes under one profiler timer.
The default 6 levels require 11 render passes, one downsample per level and one upsample for all but the smallest. Level 0 does about three quarters of the pixel work with 13 taps down and 9 up. Each following level has one quarter as many pixels. Removing a level saves little GPU work but removes two CPU-recorded passes, each requiring begin, viewport, draw and end calls.
By default, everything above the brightness threshold glows, including white sky. To bloom only emitters, draw them into a separate target and bloom that target. Keep the full scene as the final pass’s source. Use bright to select or modify emission:
Creates render targets that follow a size. Replaces the whole set when the size changes. Put
targets needed only sometimes in their own set and create that set when needed. Throws for
transient targets with sampling, storage or mip levels, for multisampled targets with storage or
mip levels, and for layered targets that are multisampled, mipped or have more layers than the
device allows.
@param ― source the size it follows, such as a surface
@param ― specs a format and options per target, by name
@param ― options.resolution the fraction of each side drawn, which changes without allocating
@returns ― a set of targets you fit every frame and destroy
create(
constroot:TgpuRoot
root,
constsurface:web.Surface
surface,{
hdr:{
readonly format:"rgba16float";
readonly sampled:true;
}
hdr:{
format:"rgba16float"
format:'rgba16float',
sampled:true
sampled:true},
emission:{
readonly format:"rgba16float";
readonly sampled:true;
}
emission:{
format:"rgba16float"
format:'rgba16float',
sampled:true
sampled:true},
});
// Bloom the full emission target with a warmer tint
const
constwarm:(color:d.v3f)=>d.v3f
warm=(
color:d.v3f
color:
import d
d.
export v3f
Interface representing its WGSL vector type counterpart: vec3f or vec3.
A vector with 3 elements of type f32
Creates bloom from a chain of half-size textures. Each level downsamples with 13 taps, then a
tent filter adds it to the next larger level. The result is mip 0 of output, at half the
source size. With region, passes draw and sample only that region; changing the region
allocates nothing.
@allocates ― on resize: a new chain and the bind groups of its passes; so does a new source
@owns ― targets, a sampler, 3 pipelines, 2 bind groups and a buffer per level: the chain of glow
levels, the settings, a group for each pass, and the region each pass reads
@records ― record after whatever wrote the source; then output holds the glow.
@param ― options.source the HDR picture, read at every record
@param ― options.region the part of the source that holds the picture, read at every record
@returns ― a bloom you record every frame and destroy
Provides the HDR picture: a rendered picture, such as aa, or a function returning a
texture, such as () => screen.textures.hdr. record reads it on every call, so the texture
can be rebuilt.
Provides the current textures. A size change replaces them. Throws after destroy.
textures.
emission:targets.Texture<{
readonly format:"rgba16float";
readonly sampled:true;
}>
emission,
Options.bright?:((color:d.v3f)=>d.v3f)|undefined
Selects the linear source colour that contributes glow. This 'use gpu' function runs once
per texel of the first level. It can call threshold and carry fills with pipe. Default
threshold.
Creates the final pass of a frame. It reads the source, adds glow, tone maps, grades, applies
the vignette, encodes and dithers. It draws one triangle into the caller pass.
@allocates ― on resize: a bind group for a new source or glow
@owns ― 2 buffers, a sampler, a pipeline, 2 bind groups: the settings, the regions it reads, and a
group each for the source and the glow
@records ― record into a pass of its own on the view you give, usually the canvas's, or draw
into the caller's pass, after the bloom's record.
@param ― options.source the picture, rendered or a texture, read at every draw
@param ― options.region the part of the source that holds the picture, read at every draw
@param ― options.glow a bloom, or a glow of your own, added before tone mapping
@param ― options.exposure an adapted exposure, read on the GPU
@returns ― a final pass you draw every frame and destroy
create(
constroot:TgpuRoot
root,{
Options.format: GPUTextureFormat
Sets the output format, such as the canvas format.
Provides the picture at any size: a rendered picture, such as aa or blur, or a function
returning a texture, such as () => screen.textures.hdr. draw reads it on every call, so
the texture can be rebuilt.
Provides the current textures. A size change replaces them. Throws after destroy.
textures.
hdr:targets.Texture<{
readonly format:"rgba16float";
readonly sampled:true;
}>
hdr,
Options.glow?:finish.Rendered|undefined
Adds a bloom, or a glow of your own such as an emission target, before tone mapping. draw
reads its output and region on every call. Default none.
glow,
});
Call bloom.threshold(color) within bright to tint values above the threshold or weight them by tone.luminance. It reads bloom settings and is valid only inside bright.
A bright that reads another module carries its fill, as bright: tgpu.fn(masked).pipe(mask.inject()) does.
Creates an exposure that adapts to the picture on the GPU. Each record
averages the log luminance of 4096 filtered samples over the source in one workgroup. It then
eases the exposure towards key divided by that average, within lowest and highest. The
exposure stays in a GPU buffer, and nothing is read back.
@allocates ― on resize: a bind group for a new source
@owns ― 3 buffers, a sampler, a pipeline and a bind group: the settings, the frame's region and
time, the exposure, and a group for the source
@injects ― per-instance exposure.current, for the final pass or shaders of your own
@binds ― 1 storage: exposure.current, read-only
@records ― record after whatever wrote the source, before the final pass that reads it
@param ― options.source the linear picture, read at every record
@param ― options.region the part of the source that holds the picture, read at every record
@returns ― an exposure you record every frame and destroy
Provides the linear picture to measure, usually the final pass's source: a rendered picture,
such as aa, or a function returning a texture. record reads it on every call, so the
texture can be rebuilt.
Creates the final pass of a frame. It reads the source, adds glow, tone maps, grades, applies
the vignette, encodes and dithers. It draws one triangle into the caller pass.
@allocates ― on resize: a bind group for a new source or glow
@owns ― 2 buffers, a sampler, a pipeline, 2 bind groups: the settings, the regions it reads, and a
group each for the source and the glow
@records ― record into a pass of its own on the view you give, usually the canvas's, or draw
into the caller's pass, after the bloom's record.
@param ― options.source the picture, rendered or a texture, read at every draw
@param ― options.region the part of the source that holds the picture, read at every draw
@param ― options.glow a bloom, or a glow of your own, added before tone mapping
@param ― options.exposure an adapted exposure, read on the GPU
@returns ― a final pass you draw every frame and destroy
create(
constroot:TgpuRoot
root,{
Options.format: GPUTextureFormat
Sets the output format, such as the canvas format.
Provides the picture at any size: a rendered picture, such as aa or blur, or a function
returning a texture, such as () => screen.textures.hdr. draw reads it on every call, so
the texture can be rebuilt.
Multiplies settings.exposure by an exposure adapted to the picture on the GPU, such as one
from exposure.create recorded before this pass. Default none.
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
Rebuilds all textures if the source size changed, destroying the old textures. Updates
regions for the current resolution. Returns true after a rebuild so callers can update bind
groups that hold old textures. Call before recording passes that use the targets. Throws after
destroy.
Measures the source and moves the exposure towards its target by dt seconds of adaptation,
the frame's dt by default. Record it after whatever wrote the source and before the final
pass. The first record, the first after reset, and one given an encoder without dt
take the target at once. Optional timer writes measure the pass.
Opens a pass on view, such as surface.view(frame), draws into it and ends it. A
viewport draws the picture into that rectangle and clears the rest, transparent with
alpha: 'premultiplied' and black otherwise. Optional timer writes measure the pass.
record(
frame:frames.Frame
frame,
constsurface:web.Surface
surface.
Surface.view(frame: frames.Frame): GPUTextureView
Returns a view of the current canvas texture, created once per texture. Applies pending size
changes first, which a pass using context would skip.
view(
frame:frames.Frame
frame));
}),
);
record(frame) averages the log luminance of 4096 samples over the source and moves the exposure towards key divided by that average, within lowest and highest. The exposure stays on the GPU, so the final pass of the same frame reads it.
The exposure rises at rise and falls at fall, per second, over the frame’s dt: each second closes 1 - e^-rise of the remaining stops, as clock.ease does. By default it falls three times as fast as it rises, so a flash dims the picture quickly and a dark scene brightens slowly. The first record takes the target at once, and so does the first after eye.reset(), such as after a camera cut.
With an encoder in place of the frame, give the seconds yourself, eye.record(encoder, { dt }). Without dt, it takes the target at once.
final.settings.exposure multiplies the adapted exposure, so it trims the look as before.
A second view, such as a picture-in-picture camera, takes its own exposure.create and final pass.
Shaders of your own read the value through exposure.current with root.pipe(eye.inject()).
eye.settings patches like the other settings. Its fields don’t overlap the final pass’s or the bloom’s.
Field
Default
key
0.18
Average luminance the exposed picture aims for, mid grey.
lowest
1/16
Lowest exposure, for the brightest pictures.
highest
16
Highest exposure, for the darkest pictures.
rise
1
How fast exposure rises after the picture darkens, per second.
fall
3
How fast exposure falls after the picture brightens, per second.
final.settings and glow.settings are uniforms. Their initial values combine defaults with the settings option. Use TypeGPU’s patch when settings change. It uploads supplied fields and skips fields absent from that uniform. Since the fields do not overlap, one object can patch both:
Creates bloom from a chain of half-size textures. Each level downsamples with 13 taps, then a
tent filter adds it to the next larger level. The result is mip 0 of output, at half the
source size. With region, passes draw and sample only that region; changing the region
allocates nothing.
@allocates ― on resize: a new chain and the bind groups of its passes; so does a new source
@owns ― targets, a sampler, 3 pipelines, 2 bind groups and a buffer per level: the chain of glow
levels, the settings, a group for each pass, and the region each pass reads
@records ― record after whatever wrote the source; then output holds the glow.
@param ― options.source the HDR picture, read at every record
@param ― options.region the part of the source that holds the picture, read at every record
@returns ― a bloom you record every frame and destroy
Provides the HDR picture: a rendered picture, such as aa, or a function returning a
texture, such as () => screen.textures.hdr. record reads it on every call, so the texture
can be rebuilt.
Creates the final pass of a frame. It reads the source, adds glow, tone maps, grades, applies
the vignette, encodes and dithers. It draws one triangle into the caller pass.
@allocates ― on resize: a bind group for a new source or glow
@owns ― 2 buffers, a sampler, a pipeline, 2 bind groups: the settings, the regions it reads, and a
group each for the source and the glow
@records ― record into a pass of its own on the view you give, usually the canvas's, or draw
into the caller's pass, after the bloom's record.
@param ― options.source the picture, rendered or a texture, read at every draw
@param ― options.region the part of the source that holds the picture, read at every draw
@param ― options.glow a bloom, or a glow of your own, added before tone mapping
@param ― options.exposure an adapted exposure, read on the GPU
@returns ― a final pass you draw every frame and destroy
create(
constroot:TgpuRoot
root,{
Options.format: GPUTextureFormat
Sets the output format, such as the canvas format.
Provides the picture at any size: a rendered picture, such as aa or blur, or a function
returning a texture, such as () => screen.textures.hdr. draw reads it on every call, so
the texture can be rebuilt.
Creates the final pass of a frame. It reads the source, adds glow, tone maps, grades, applies
the vignette, encodes and dithers. It draws one triangle into the caller pass.
@allocates ― on resize: a bind group for a new source or glow
@owns ― 2 buffers, a sampler, a pipeline, 2 bind groups: the settings, the regions it reads, and a
group each for the source and the glow
@records ― record into a pass of its own on the view you give, usually the canvas's, or draw
into the caller's pass, after the bloom's record.
@param ― options.source the picture, rendered or a texture, read at every draw
@param ― options.region the part of the source that holds the picture, read at every draw
@param ― options.glow a bloom, or a glow of your own, added before tone mapping
@param ― options.exposure an adapted exposure, read on the GPU
@returns ― a final pass you draw every frame and destroy
create(
constroot:TgpuRoot
root,{
Options.format: GPUTextureFormat
Sets the output format, such as the canvas format.
Provides the picture at any size: a rendered picture, such as aa or blur, or a function
returning a texture, such as () => screen.textures.hdr. draw reads it on every call, so
the texture can be rebuilt.
Grades or tints the colour after tone mapping and before the vignette, encoding and dither.
It receives the colour and output UV coordinates from 0 to 1. Read other pixels with
finish.picture(uv) and glow with finish.glow(uv). Default none.
Use finish.picture(uv) inside grade to read a neighbouring source pixel with glow, exposure and tone mapping applied. finish.glow(uv) reads glow before glowIntensity scales it and returns zero if absent. This grade adds red and blue fringes like lens chromatic aberration:
import{
import finish
finish}from'@typegpu/kit';
const
constfringe:(color:d.v3f,uv:d.v2f)=>d.v3f
fringe=(
color:d.v3f
color:
import d
d.
export v3f
Interface representing its WGSL vector type counterpart: vec3f or vec3.
A vector with 3 elements of type f32
v3f,
uv:d.v2f
uv:
import d
d.
export v2f
Interface representing its WGSL vector type counterpart: vec2f or vec2.
A vector with 2 elements of type f32
v2f)=>{
'use gpu';
const
constshift:d.v2f
shift=(
uv:d.v2f
uv-0.5)*0.008;
return
import d
d.
constvec3f:d.Vec3f
(x:number,y:number,z:number)=>d.v3f(+5 overloads)
vec3f(
import finish
finish.
constpicture:(uv:d.v2f)=>d.v3f
Samples the source with glow, exposure and tone mapping at output UV coordinates from 0 to 1.
This is the colour passed to grade. Call it only from the final pass grade function.
picture(
uv:d.v2f
uv+
constshift:d.v2f
shift).
v3f.x: number
x,
color:d.v3f
color.
v3f.y: number
y,
import finish
finish.
constpicture:(uv:d.v2f)=>d.v3f
Samples the source with glow, exposure and tone mapping at output UV coordinates from 0 to 1.
This is the colour passed to grade. Call it only from the final pass grade function.
Creates the final pass of a frame. It reads the source, adds glow, tone maps, grades, applies
the vignette, encodes and dithers. It draws one triangle into the caller pass.
@allocates ― on resize: a bind group for a new source or glow
@owns ― 2 buffers, a sampler, a pipeline, 2 bind groups: the settings, the regions it reads, and a
group each for the source and the glow
@records ― record into a pass of its own on the view you give, usually the canvas's, or draw
into the caller's pass, after the bloom's record.
@param ― options.source the picture, rendered or a texture, read at every draw
@param ― options.region the part of the source that holds the picture, read at every draw
@param ― options.glow a bloom, or a glow of your own, added before tone mapping
@param ― options.exposure an adapted exposure, read on the GPU
@returns ― a final pass you draw every frame and destroy
create(
constroot:TgpuRoot
root,{
Options.format: GPUTextureFormat
Sets the output format, such as the canvas format.
Provides the picture at any size: a rendered picture, such as aa or blur, or a function
returning a texture, such as () => screen.textures.hdr. draw reads it on every call, so
the texture can be rebuilt.
Grades or tints the colour after tone mapping and before the vignette, encoding and dither.
It receives the colour and output UV coordinates from 0 to 1. Read other pixels with
finish.picture(uv) and glow with finish.glow(uv). Default none.
grade:
constfringe:(color:d.v3f,uv:d.v2f)=>d.v3f
fringe,
});
Each finish.picture call repeats source and glow reads and tone mapping. The fringe example triples that work. For sharpening, sample neighbours std.fwidth(uv) apart, one texel.
These functions work only inside the final pass’s grade. Other uses fail shader compilation.
For a lookup table, capture a 3D texture view and sampler in the grade. If the table can change, read it through a filled accessor, for example grade: tgpu.fn(looked).pipe((cfg) => cfg.with(table, () => view.$)).
A grade can show any sampled target instead of the picture, such as depth while you tune fog. Read a target that follows the canvas through a bindings.layout part, and set the shared group on the pass before draw:
Creates render targets that follow a size. Replaces the whole set when the size changes. Put
targets needed only sometimes in their own set and create that set when needed. Throws for
transient targets with sampling, storage or mip levels, for multisampled targets with storage or
mip levels, and for layered targets that are multisampled, mipped or have more layers than the
device allows.
@param ― source the size it follows, such as a surface
@param ― specs a format and options per target, by name
@param ― options.resolution the fraction of each side drawn, which changes without allocating
@returns ― a set of targets you fit every frame and destroy
create(
constroot:TgpuRoot
root,
constsurface:web.Surface
surface,{
hdr:{
readonly format:"rgba16float";
readonly sampled:true;
}
hdr:{
format:"rgba16float"
format:'rgba16float',
sampled:true
sampled:true},
depth:{
readonly format:"depth24plus";
readonly sampled:true;
}
depth:{
format:"depth24plus"
format:'depth24plus',
sampled:true
sampled:true},
});
const
constshown:bindings.Layout<{
readonly depth:{
readonly texture:d.WgslTextureDepth2d;
};
}>
shown=
import bindings
bindings.
functionlayout<{
readonly depth:{
readonly texture:d.WgslTextureDepth2d;
};
}>(entries:{
readonly depth:{
readonly texture:d.WgslTextureDepth2d;
};
}):bindings.Layout<{
readonly depth:{
readonly texture:d.WgslTextureDepth2d;
};
}>
Declares bindings for module shaders from the entries that tgpu.bindGroupLayout takes. Define
the layout once beside the shaders. A part made with bind can bind its resources directly.
Call share before creating pipelines to put the part in a shared layout.
@param ― entries the bindings, as tgpu.bindGroupLayout takes them
@returns ― a layout whose bind makes a part from resources
Combines parts from modules or your own code in one layout. Call it before creating pipelines.
Set its group on each pass with pass.setBindGroup(shared.layout, shared.group()), or give it to
passes.create as shared, which sets it in every pass it begins. Every pipeline in that pass
that reads a part then uses the shared group.
@param ― parts parts from any modules and your own, by key
@returns ― a layout you set on each pass, with the group for the parts' resources
share(
constroot:TgpuRoot
root,{
shown:bindings.Bound<{
readonly depth:{
readonly texture:d.WgslTextureDepth2d;
};
}>
shown:
constpart:bindings.Bound<{
readonly depth:{
readonly texture:d.WgslTextureDepth2d;
};
}>
part});// before `finish.create`
// Depth as grey, white at the eye
const
constdepthOf:(_color:d.v3f,uv:d.v2f)=>d.v3f
depthOf=(
_color:d.v3f
_color:
import d
d.
export v3f
Interface representing its WGSL vector type counterpart: vec3f or vec3.
A vector with 3 elements of type f32
v3f,
uv:d.v2f
uv:
import d
d.
export v2f
Interface representing its WGSL vector type counterpart: vec2f or vec2.
A vector with 2 elements of type f32
Creates the final pass of a frame. It reads the source, adds glow, tone maps, grades, applies
the vignette, encodes and dithers. It draws one triangle into the caller pass.
@allocates ― on resize: a bind group for a new source or glow
@owns ― 2 buffers, a sampler, a pipeline, 2 bind groups: the settings, the regions it reads, and a
group each for the source and the glow
@records ― record into a pass of its own on the view you give, usually the canvas's, or draw
into the caller's pass, after the bloom's record.
@param ― options.source the picture, rendered or a texture, read at every draw
@param ― options.region the part of the source that holds the picture, read at every draw
@param ― options.glow a bloom, or a glow of your own, added before tone mapping
@param ― options.exposure an adapted exposure, read on the GPU
@returns ― a final pass you draw every frame and destroy
create(
constroot:TgpuRoot
root,{
Options.format: GPUTextureFormat
Sets the output format, such as the canvas format.
Provides the picture at any size: a rendered picture, such as aa or blur, or a function
returning a texture, such as () => screen.textures.hdr. draw reads it on every call, so
the texture can be rebuilt.
Grades or tints the colour after tone mapping and before the vignette, encoding and dither.
It receives the colour and output UV coordinates from 0 to 1. Read other pixels with
finish.picture(uv) and glow with finish.glow(uv). Default none.
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
Rebuilds all textures if the source size changed, destroying the old textures. Updates
regions for the current resolution. Returns true after a rebuild so callers can update bind
groups that hold old textures. Call before recording passes that use the targets. Throws after
destroy.
Replaces resources without creating pipelines. The next shared group uses the replacements.
Throws if a pipeline already binds the resources directly, because that pipeline would keep
the old resources.
Provides the current textures. A size change replaces them. Throws after destroy.
textures.
depth:targets.Texture<{
readonly format:"depth24plus";
readonly sampled:true;
}>
depth});
// the scene, into hdr and depth
const
constoutput:TgpuRenderPass
output=
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.
Contains every part's entries. Each entry is named key_name using the part's key in share.
layout,
constshared:bindings.Shared
shared.
Shared.group(): TgpuBindGroup
Returns the group for the current resources, for pass.setBindGroup(shared.layout, …).
Creates a group only when a resource has changed. Otherwise, it allocates nothing.
group());
constfinal:finish.Finish
final.
Finish.draw(pass: TgpuRenderCommands): void
Draws into the caller's pass, which usually targets the canvas.
draw(
constoutput:TgpuRenderPass
output);
constoutput:TgpuRenderPass
output.
TgpuRenderPass.end(): void
Completes the recording of this render pass
end();
}),
);
fit() returns true after it rebuilds the targets. Replacing the part’s texture then keeps the pipeline. Without the share, replace throws at the first resize; bind the part with unshared to have finish.create’s pipeline throw as it builds instead.
With glow, the final pass uses 3 bind groups and the shared group is the fourth, WebGPU’s limit.
The final pass still encodes, vignettes and dithers what the grade returns. Pass encode: false and set vignette and dither to 0 to see the stored values unchanged.
The same grade shows what a module computes on the way to the picture. Ambient occlusion stores visibility in red, so a final pass can take its output as the source and show red as grey:
const
constgrey:(color:d.v3f)=>d.v3f
grey=(
color:d.v3f
color:
import d
d.
export v3f
Interface representing its WGSL vector type counterpart: vec3f or vec3.
A vector with 3 elements of type f32
Creates the final pass of a frame. It reads the source, adds glow, tone maps, grades, applies
the vignette, encodes and dithers. It draws one triangle into the caller pass.
@allocates ― on resize: a bind group for a new source or glow
@owns ― 2 buffers, a sampler, a pipeline, 2 bind groups: the settings, the regions it reads, and a
group each for the source and the glow
@records ― record into a pass of its own on the view you give, usually the canvas's, or draw
into the caller's pass, after the bloom's record.
@param ― options.source the picture, rendered or a texture, read at every draw
@param ― options.region the part of the source that holds the picture, read at every draw
@param ― options.glow a bloom, or a glow of your own, added before tone mapping
@param ― options.exposure an adapted exposure, read on the GPU
@returns ― a final pass you draw every frame and destroy
create(
constroot:TgpuRoot
root,{
Options.format: GPUTextureFormat
Sets the output format, such as the canvas format.
Provides the picture at any size: a rendered picture, such as aa or blur, or a function
returning a texture, such as () => screen.textures.hdr. draw reads it on every call, so
the texture can be rebuilt.
source:
constocclusion:ao.Ao
occlusion,
Options.tone?: Tone |null|undefined
Maps linear source colours to display range with aces, neutral, reinhard or a custom
curve. Use null for sources already in display range. Default neutral.
tone:null,
Options.encode?: boolean |undefined
Applies the sRGB transfer function in the shader. Use false for encoded colours, such as
pixel art painted in screen colours. Formats ending in -srgb encode on storage. Default
true unless format ends in -srgb.
Grades or tints the colour after tone mapping and before the vignette, encoding and dither.
It receives the colour and output UV coordinates from 0 to 1. Read other pixels with
finish.picture(uv) and glow with finish.glow(uv). Default none.
A surface with alphaMode: 'premultiplied' shows what is behind it, such as a web page. Draw the scene in premultiplied colour into a target cleared to transparent, and give the final pass alpha: 'premultiplied':
Controls canvas transparency. With premultiplied, alpha below 1 reveals what is behind the
canvas, and colours must be premultiplied by alpha. Default opaque.
Creates render targets that follow a size. Replaces the whole set when the size changes. Put
targets needed only sometimes in their own set and create that set when needed. Throws for
transient targets with sampling, storage or mip levels, for multisampled targets with storage or
mip levels, and for layered targets that are multisampled, mipped or have more layers than the
device allows.
@param ― source the size it follows, such as a surface
@param ― specs a format and options per target, by name
@param ― options.resolution the fraction of each side drawn, which changes without allocating
@returns ― a set of targets you fit every frame and destroy
Creates bloom from a chain of half-size textures. Each level downsamples with 13 taps, then a
tent filter adds it to the next larger level. The result is mip 0 of output, at half the
source size. With region, passes draw and sample only that region; changing the region
allocates nothing.
@allocates ― on resize: a new chain and the bind groups of its passes; so does a new source
@owns ― targets, a sampler, 3 pipelines, 2 bind groups and a buffer per level: the chain of glow
levels, the settings, a group for each pass, and the region each pass reads
@records ― record after whatever wrote the source; then output holds the glow.
@param ― options.source the HDR picture, read at every record
@param ― options.region the part of the source that holds the picture, read at every record
@returns ― a bloom you record every frame and destroy
Provides the HDR picture: a rendered picture, such as aa, or a function returning a
texture, such as () => screen.textures.hdr. record reads it on every call, so the texture
can be rebuilt.
Creates the final pass of a frame. It reads the source, adds glow, tone maps, grades, applies
the vignette, encodes and dithers. It draws one triangle into the caller pass.
@allocates ― on resize: a bind group for a new source or glow
@owns ― 2 buffers, a sampler, a pipeline, 2 bind groups: the settings, the regions it reads, and a
group each for the source and the glow
@records ― record into a pass of its own on the view you give, usually the canvas's, or draw
into the caller's pass, after the bloom's record.
@param ― options.source the picture, rendered or a texture, read at every draw
@param ― options.region the part of the source that holds the picture, read at every draw
@param ― options.glow a bloom, or a glow of your own, added before tone mapping
@param ― options.exposure an adapted exposure, read on the GPU
@returns ― a final pass you draw every frame and destroy
create(
constroot:TgpuRoot
root,{
Options.format: GPUTextureFormat
Sets the output format, such as the canvas format.
Provides the picture at any size: a rendered picture, such as aa or blur, or a function
returning a texture, such as () => screen.textures.hdr. draw reads it on every call, so
the texture can be rebuilt.
Provides the current textures. A size change replaces them. Throws after destroy.
textures.
hdr:targets.Texture<{
readonly format:"rgba16float";
readonly sampled:true;
}>
hdr,
Options.alpha?:"opaque"|"premultiplied"|undefined
Selects output alpha handling. premultiplied requires premultiplied source colour,
preserves alpha and raises it where glow adds light. The output remains premultiplied so a
surface can show its background. Default opaque, which writes alpha 1.
alpha:'premultiplied',
Options.glow?:finish.Rendered|undefined
Adds a bloom, or a glow of your own such as an emission target, before tone mapping. draw
reads its output and region on every call. Default none.
glow,
});
Divide out alpha before the curve and grade. Multiply it back after dither so clear pixels stay clear and noise does not show over the page.
The glow raises the alpha by its brightest channel, so it shows over the page around what casts it.
The vignette fades the corners out, colour and alpha together, instead of darkening them, which would tint the page.
Custom screen shaders can finish with a tone curve, linearToSrgb from @typegpu/color and tone.dither(encoded, pixel, steps) to reduce banding. Import curves, luminance and dither from @typegpu/kit/tone without creating bloom or a final pass.
Adds triangular noise to encoded colour, seeded by pixel. steps sets the amplitude in
8-bit steps. This reduces banding in dark 8-bit gradients. The final pass applies it before
storing output.
dither(
functionlinearToSrgb(linear:d.v3f):d.v3f
linearToSrgb(
import tone
tone.
constneutral:(input:d.v3f)=>d.v3f
Applies Khronos PBR Neutral. It preserves hue and saturation below the highlights, then
reduces them.
tone and grade compile into pipelines. Create another final pass to switch them at runtime.
Built-in curves do not use Oklab. Per-channel curves shift orange toward yellow and blue toward cyan. Supply a custom tone using conversions from @typegpu/color.
linearToSrgb passes negative values through; a unorm target clamps them as it stores.
exposure meters with one compute pass of one 256-thread workgroup, the same at any resolution. Pixels darker than 0.0001 count as 0.0001, and every sample weighs the same, with no weighting towards the centre.
Final-pass stage order is fixed. For a custom vignette or encoding, implement it in grade and set vignette: 0 and encode: false.