Capítulo 838 de 859
How EffectComposer chains post-processing Passes by ping-ponging between two render targets, and how to write a custom ShaderPass when the built-in passes (bloom, film grain, etc.) aren't enough.
EffectComposer: creates two internal render targets and applies each added Pass in order, feeding one target's output as the next pass's input and swapping which target is "current" as it goes.enabled (whether to run this pass at all), needsSwap (whether to swap the two render targets after this pass), clear (whether to clear before rendering this pass), and renderToScreen (render to the canvas instead of a render target — usually left alone, since the last pass in the chain does this automatically).RenderPass (renders the actual scene, normally first), BloomPass (blurs a smaller copy of the input and adds it back for a glow effect), FilmPass (adds noise/scanlines), OutputPass (sRGB conversion and tone mapping, normally last).composer.render(deltaTime): replaces renderer.render() in the animation loop; deltaTime (seconds since last frame) is passed through to any time-based effects like FilmPass.ShaderPass: wraps a custom GLSL shader (with a standard, rarely-changed vertex shader) as a pass; the fragment shader reads the previous pass's result from the tDiffuse sampler and writes a modified color.const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
composer.addPass(new ShaderPass({
uniforms: { tDiffuse: { value: null }, color: { value: new THREE.Color(1, 1, 1) } },
fragmentShader: `
uniform sampler2D tDiffuse;
uniform vec3 color;
varying vec2 vUv;
void main() {
vec4 previousPassColor = texture2D(tDiffuse, vUv);
gl_FragColor = vec4(previousPassColor.rgb * color, previousPassColor.a);
}
`,
}));
ShaderPass that multiplies the previous pass's output by a color, using the standard tDiffuse input.EffectComposer manages two render targets and feeds each pass's output into the next, swapping targets as it goes.RenderPass normally starts the chain and OutputPass (color-space + tone mapping) normally ends it.renderer.render() with composer.render(deltaTime) and keep the composer's size synced to the canvas on resize.ShaderPass reading tDiffuse (the previous pass's texture) in its fragment shader — the vertex shader is boilerplate you rarely need to change.WebGLRenderer under the hood.