Render targets are named off-screen textures that passes can read from and write to. They allow techniques like downsampled blur pyramids, multi-resolution effects, and intermediate computation buffers.
Declaring render targets
Render targets are declared as a
renderTargetsFragCanvas<FragCanvas
{material}
renderTargets={{
half: { scale: 0.5 },
bloom: { width: 640, height: 360, format: 'rgba16float' }
}}
passes={passes}
/><FragCanvas
{material}
renderTargets={{
half: { scale: 0.5 },
bloom: { width: 640, height: 360, format: 'rgba16float' }
}}
passes={passes}
/>The map keys become the names used to access targets in passes.
Using named targets as pass slots
Named target keys can be used directly in
RenderPass.inputRenderPass.outputconst passes = [
new ShaderPass({
needsSwap: false,
output: 'bloom'
}),
new ShaderPass({
needsSwap: false,
input: 'bloom',
output: 'canvas'
})
];const passes = [
new ShaderPass({
needsSwap: false,
output: 'bloom'
}),
new ShaderPass({
needsSwap: false,
input: 'bloom',
output: 'canvas'
})
];Rules:
- Named slots must exist in .
renderTargets - Named outputs are only valid with .
needsSwap: false - is reserved for
needsSwap: true.source -> target
RenderTargetDefinition fields
| Field | Type | Default | Description |
|---|---|---|---|
width | number | undefined | Explicit width in pixels (floored, minimum 1) |
height | number | undefined | Explicit height in pixels (floored, minimum 1) |
scale | number | 1 | Scale factor relative to canvas size |
format | GPUTextureFormat | Canvas format | Texture format |
Resolution rules
Each dimension is resolved independently:
- If or
widthis explicitly set, that value is used (height).Math.max(1, Math.floor(value)) - If a dimension is not set, it is computed as .
Math.max(1, Math.floor(canvasDimension * scale)) - If is not set, it defaults to
scale(full canvas resolution).1
Examples
| Definition | Canvas 1920×1080 | Result |
|---|---|---|
{ scale: 0.5 } | 1920×1080 | 960×540 |
{ scale: 0.25 } | 1920×1080 | 480×270 |
{ width: 256, height: 256 } | any | 256×256 |
{ width: 512 } | 1920×1080 | 512×1080 |
{} | 1920×1080 | 1920×1080 |
Naming rules
Target keys must be WGSL-safe identifiers:
[A-Za-z_][A-Za-z0-9_]*Validation
| Condition | Result |
|---|---|
scale <= 0 | Throws |
scaleNaNInfinity | Throws |
width <= 0height <= 0 | Throws |
widthheightNaNInfinity | Throws |
| Invalid key identifier | Throws |
| Pass writes undeclared named slot | Throws during render-graph planning |
| Pass reads undeclared named slot | Throws during render-graph planning |
| Pass reads named slot before first write | Throws during render-graph planning |
Accessing targets in passes
Render targets are available in the
RenderPassContexttargetsrender(context: RenderPassContext): void {
const bloomTarget = context.targets.bloom;
if (bloomTarget) {
// Use bloomTarget.texture, bloomTarget.view, etc.
}
}render(context: RenderPassContext): void {
const bloomTarget = context.targets.bloom;
if (bloomTarget) {
// Use bloomTarget.texture, bloomTarget.view, etc.
}
}Named targets are accessed through
context.targetsLifecycle
The renderer manages render target textures automatically:
| Event | Action |
|---|---|
| New target added | GPU texture allocated |
| Canvas resizes (for scaled targets) | Texture reallocated at new resolution |
| Target definition changes | Texture reallocated |
| Target removed from map | GPU texture destroyed |
| Renderer destroyed | All target textures destroyed |
Signature-based change detection
Render target definitions are compared each frame using a deterministic signature:
key:format:widthxheightPractical patterns
Half-resolution blur
const renderTargets = {
halfRes: { scale: 0.5 }
};
// Use halfRes as an intermediate for blur passesconst renderTargets = {
halfRes: { scale: 0.5 }
};
// Use halfRes as an intermediate for blur passesFixed-resolution computation buffer
const renderTargets = {
compute: { width: 256, height: 256, format: 'rgba16float' }
};const renderTargets = {
compute: { width: 256, height: 256, format: 'rgba16float' }
};HDR intermediate
const renderTargets = {
hdr: { format: 'rgba16float' }
};
// Full canvas resolution but in 16-bit float for high dynamic rangeconst renderTargets = {
hdr: { format: 'rgba16float' }
};
// Full canvas resolution but in 16-bit float for high dynamic range