Post-processing refers to effects applied to an entire rendered image after the 3D scene has been drawn. Three.js offers robust post-processing capabilities to enhance visual realism and artistic effects, including Bloom, FXAA (Fast Approximate Anti-aliasing), and Depth of Field (DoF). These effects are typically managed using the EffectComposer.
To apply post-processing effects in Three.js, you generally follow these steps:
EffectComposer: Instead of rendering directly to the WebGLRenderer, you render to an EffectComposer.RenderPass: The first pass added to the composer is usually a RenderPass, which renders your scene into the composer's internal render target.OutputPass: Often, an OutputPass is added as the final pass to handle tone mapping and output the result to the screen.composer.render() instead of renderer.render().You will need to import the necessary passes from three/examples/jsm/postprocessing/.
The Bloom effect simulates the optical phenomenon where light from bright areas of an image appears to bleed into surrounding darker areas, creating a glowing effect.
UnrealBloomPass.strength (intensity of the bloom), radius (spread of the bloom), and threshold (luminance level above which pixels will bloom).FXAA is a post-processing anti-aliasing technique that smooths jagged edges in a rendered image. It's a relatively fast method suitable for real-time applications.
ShaderPass with an FXAA shader.Depth of Field simulates the focus of a camera lens, where objects at a certain distance are in sharp focus, while objects closer or further away appear blurred.
DepthOfFieldPass or custom shaders that utilize depth information.focalLength, focalDepth, fstop, and maxblur, which control the focus plane and the intensity of the blur.This example shows a conceptual setup for post-processing. To see the effects, you would typically add specific passes like UnrealBloomPass, ShaderPass (for FXAA), or DepthOfFieldPass to the composer.
import *s THREE from 'three';
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
// import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
// import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
// import { FXAAShader } from 'three/addons/shaders/FXAAShader.js';
// Scene, Camera, Renderer setup (assuming these are already defined)
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Add a cube to the scene
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 5;
// 1. Initialize EffectComposer
const composer = new EffectComposer(renderer);
// 2. Add RenderPass
composer.addPass(new RenderPass(scene, camera));
// 3. Add Effect Passes (uncomment and configure as needed)
// const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85);
// composer.addPass(bloomPass);
// const fxaaPass = new ShaderPass(FXAAShader);
// fxaaPass.material.uniforms[ 'resolution' ].value.x = 1 / ( window.innerWidth * window.devicePixelRatio );
// fxaaPass.material.uniforms[ 'resolution' ].value.y = 1 / ( window.innerHeight * window.devicePixelRatio );
// composer.addPass(fxaaPass);
// Animation loop
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
// Render with composer instead of renderer
composer.render();
}
animate();
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
composer.setSize(window.innerWidth, window.innerHeight);
// Update FXAA resolution if used
// if (fxaaPass) {
// fxaaPass.material.uniforms[ 'resolution' ].value.x = 1 / ( window.innerWidth * window.devicePixelRatio );
// fxaaPass.material.uniforms[ 'resolution' ].value.y = 1 / ( window.innerHeight * window.devicePixelRatio );
// }
});