ShaderPassRenderer
ShaderPassRenderer applies one or more ShaderPass or ShaderPassPipeline definitions to a source texture and either renders the result back to a texture or draws it to the screen.
Internally it uses ClipSpace, BackgroundTextureModel, and SwapFramebuffers to manage the pass chain.
Usage
import {ShaderPassRenderer} from '@luma.gl/engine';
const renderer = new ShaderPassRenderer(device, {
shaderPasses: [myShaderPass, myShaderPassPipeline]
});
const outputTexture = renderer.renderToTexture({sourceTexture});
Per-draw uniforms and extra bindings can be supplied when a pass needs frame-specific inputs:
renderer.renderToScreen({
sourceTexture: sceneColorTexture,
bindings: {depthTexture: sceneDepthTexture},
uniforms: {
dof: {
depthRange: [0.1, 30],
focusDistance: 3,
blurCoefficient: 0.9,
pixelsPerMillimeter: 42
}
}
});
Routing Model
The renderer always provides two logical texture sources:
original: the original input texture passed torenderToTexture()previous: the current shared output of the pass chain
Plain ShaderPass objects may route subpasses only against those logical sources.
ShaderPassPipeline adds pipeline-global named render targets that any later step in that pipeline may read:
type ShaderPassPipeline<TargetNameT extends string = string> = {
name: string;
renderTargets?: Record<TargetNameT, ShaderPassRenderTarget>;
steps: ShaderPassPipelineStep<TargetNameT>[];
};
type ShaderPassPipelineStep<TargetNameT extends string = string> = {
shaderPass: ShaderPass;
inputs?: Record<string, ShaderPassInputSource<TargetNameT>>;
output?: 'previous' | TargetNameT;
uniforms?: Record<string, UniformValue>;
};
Each step runs an existing ShaderPass:
step.inputsis applied to the first subpass of the referenced pass.step.outputis applied to the last subpass of the referenced pass.step.uniformsis merged into every subpass as a base layer.
This lets the renderer orchestrate existing passes without turning ShaderPass.passes into nested effects.
Runtime Inputs
At draw time, the renderer merges three uniform layers for each shader pass:
- values already stored in
shaderInputs - uniforms declared on the pass or pipeline step
options.uniformspassed torenderToTexture()/renderToScreen()
Bindings follow a similar pattern:
- bindings already stored in
shaderInputsfor the current shader pass options.bindingspassed to the draw call
This makes it practical to keep one renderer alive while swapping in frame-specific resources such as a freshly rendered depth texture.
When you call shaderInputs.setProps({[passName]: {...}}), any texture bindings in that object are
stored as defaults for that specific shader pass. ShaderPassRenderer resolves those defaults per
pass, then layers options.bindings on top for per-frame overrides.
Example
This example extracts highlights into one named target, runs an existing blur pass into another, then composites back to previous:
const bloomPipeline: ShaderPassPipeline<'extract' | 'blurred'> = {
name: 'bloom',
renderTargets: {
extract: {},
blurred: {scale: [0.5, 0.5]}
},
steps: [
{
shaderPass: brightExtractPass,
inputs: {sourceTexture: 'original'},
output: 'extract',
uniforms: {threshold: 0.8}
},
{
shaderPass: gaussianBlur,
inputs: {sourceTexture: 'extract'},
output: 'blurred',
uniforms: {radius: 12}
},
{
shaderPass: bloomCompositePass,
inputs: {
sourceTexture: 'previous',
bloomTexture: 'blurred'
},
output: 'previous',
uniforms: {intensity: 1.5}
}
]
};
Types
ShaderPassRendererProps
export type ShaderPassRendererProps = {
shaderPasses: (ShaderPass | ShaderPassPipeline)[];
shaderInputs?: ShaderInputs;
};
Properties
shaderInputs
Shader-input manager used to store pass uniforms.
swapFramebuffers
Double-buffered framebuffer pair used while running the shared previous chain.
passRenderers
Internal per-entry renderers. A renderer for a ShaderPassPipeline owns that pipeline's named render targets.
textureModel
Fullscreen background-texture model used when copying or presenting results.
Methods
constructor(device: Device, props: ShaderPassRendererProps)
Initializes the shader passes, shader inputs, swap framebuffers, and presentation model.
destroy(): void
Destroys owned pass renderers, swap framebuffers, and texture model.
resize(size?: [number, number]): void
Resizes the internal swap framebuffers and all pipeline render targets to match the provided size or the current canvas size.
Named targets respect their declared scale. For example, a target with scale: [0.5, 0.5] is resized to half width and half height.
renderToScreen(options): boolean
Runs the pass chain and then draws the result into the device's current framebuffer.
renderToScreen(options: {
sourceTexture: DynamicTexture | Texture;
uniforms?: Record<string, Record<string, unknown>>;
bindings?: Record<string, Binding | DynamicTexture>;
}): boolean
Returns false when the source texture is not ready yet.
renderToTexture(options): Texture | null
Runs the pass chain and returns the output texture.
renderToTexture(options: {
sourceTexture: DynamicTexture | Texture;
uniforms?: Record<string, Record<string, unknown>>;
bindings?: Record<string, Binding | DynamicTexture>;
}): Texture | null
Remarks
sourceTexturemay be aDynamicTextureor a readyTexture.uniformsmay supply per-draw shader module uniforms keyed by shader pass name.bindingsmay supply per-draw texture bindings keyed by shader binding name.- Two internal framebuffers are used for ping-pong rendering through the shared
previoussequence. - Named render targets are declared only on
ShaderPassPipeline, not onShaderPass. - Target names
originalandpreviousare reserved and may not be used as pipeline target names. - A plain
ShaderPassused outside a pipeline may only referenceoriginalandprevious. - The renderer throws if a pass or pipeline step references an unknown input source or output target.
- The renderer throws if a subpass tries to read from and write to the same named render target in one draw.