How to Use CopyShader in Three.js EffectComposer
This article explains how to use the CopyShader in
Three.js to render the final post-processing results of an
EffectComposer directly to the screen. You will learn how
to set up the post-processing pipeline, configure a
ShaderPass with the CopyShader, and update
your animation loop to output the composed frame to the canvas.
Understanding the Role of CopyShader
In Three.js, the EffectComposer manages a chain of
post-processing passes. It uses two internal render targets (read and
write buffers) to perform double-buffering. To display the final result
of these combined effects on the screen rather than keeping them in an
off-screen buffer, you must output the final pass to the canvas.
The CopyShader is a simple utility shader that copies
the contents of one texture buffer directly to another (or to the
screen). By wrapping CopyShader in a
ShaderPass and setting its renderToScreen
property to true, you instruct the composer to write the
final image data to the device screen.
Step-by-Step Implementation
1. Import the Necessary Modules
First, import the required post-processing classes and shaders from the Three.js examples folder:
import * as THREE from 'three';
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
import { CopyShader } from 'three/examples/jsm/shaders/CopyShader.js';2. Initialize the EffectComposer
Create an instance of EffectComposer by passing your
WebGLRenderer to it.
const renderer = new THREE.WebGLRenderer({ canvas });
const composer = new EffectComposer(renderer);3. Add the RenderPass
The first pass in your composer chain should be a
RenderPass. This pass renders your basic 3D scene and
camera view into the composer’s internal buffers.
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);4. Create and Configure the CopyShader Pass
To output the final result to the screen, instantiate a
ShaderPass using the CopyShader. Ensure you
set the renderToScreen property of this pass to
true.
const copyPass = new ShaderPass(CopyShader);
copyPass.renderToScreen = true;
composer.addPass(copyPass);If you have other effect passes (like bloom, film grain, or
depth-of-field), add them to the composer before adding the
copyPass. The copyPass should always be the
last pass added to the chain.
5. Update the Animation Loop
To display the post-processed frame, replace your standard
renderer.render(scene, camera) call in your animation loop
with composer.render().
function animate() {
requestAnimationFrame(animate);
// Perform any object rotations or animations here
// Render the scene through the composer
composer.render();
}
animate();Important Note for Modern Three.js Versions
In recent versions of Three.js (r124 and newer), the
EffectComposer automatically sets the last pass in the
chain to render to the screen. If you are using a modern version of
Three.js, you often do not need to manually add a
CopyShader at the end of your chain, as the composer
handles this internally. However, manually using the
CopyShader remains necessary if you are working with legacy
codebases, custom rendering chains, or multiple composers that blend
together.