EffectComposer 是 Three.js 中用于实现后期处理效果的核心类,它允许你将多个渲染效果组合在一起,创建复杂的视觉特效。
EffectComposer 是一个管理后期处理通道(passes)的容器,它按照顺序执行这些通道,最终将结果渲染到屏幕或渲染目标。
EffectComposer - 主控制器
RenderPass - 基础渲染通道
ShaderPass - 着色器效果通道
各种效果通道 - 如 BloomPass、FilmPass、GlitchPass 等
javascript
// 需要引入后期处理相关库
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';
javascript
// 1. 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
// 2. 创建 EffectComposer
const composer = new EffectComposer(renderer);
// 3. 创建基础渲染通道
const renderPass = new RenderPass(scene, camera);
// 4. 添加通道到 composer
composer.addPass(renderPass);
// 5. 渲染循环中使用 composer 而不是 renderer
function animate() {
requestAnimationFrame(animate);
composer.render(); // 替代 renderer.render(scene, camera)
}
javascript
// 导入所需模块
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 { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass.js';
import { FilmPass } from 'three/examples/jsm/postprocessing/FilmPass.js';
import { GlitchPass } from 'three/examples/jsm/postprocessing/GlitchPass.js';
class PostProcessingDemo {
constructor() {
this.initScene();
this.initComposer();
this.animate();
}
initScene() {
// 创建场景、相机、渲染器等基础Three.js设置
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
this.renderer = new THREE.WebGLRenderer({ antialias: true });
this.renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(this.renderer.domElement);
// 添加一些测试物体
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
this.cube = new THREE.Mesh(geometry, material);
this.scene.add(this.cube);
// 添加灯光
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(1, 1, 1);
this.scene.add(light);
this.camera.position.z = 5;
}
initComposer() {
// 创建 EffectComposer
this.composer = new EffectComposer(this.renderer);
// 1. 基础渲染通道 - 必须放在第一位
const renderPass = new RenderPass(this.scene, this.camera);
this.composer.addPass(renderPass);
// 2. 添加辉光效果
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5, // 强度
0.4, // 半径
0.85 // 阈值
);
this.composer.addPass(bloomPass);
// 3. 添加胶片颗粒效果
const filmPass = new FilmPass(
0.35, // 噪声强度
false // 是否灰度
);
this.composer.addPass(filmPass);
// 4. 添加故障效果
const glitchPass = new GlitchPass();
glitchPass.goWild = false; // 控制是否随机故障
this.composer.addPass(glitchPass);
// 5. 添加输出通道(将结果渲染到屏幕)
const outputPass = new ShaderPass(CopyShader);
outputPass.renderToScreen = true; // 重要:最后一个通道需要设置这个
this.composer.addPass(outputPass);
// 设置像素比例,避免模糊
this.composer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
}
animate() {
requestAnimationFrame(() => this.animate());
// 更新动画
this.cube.rotation.x += 0.01;
this.cube.rotation.y += 0.01;
// 使用 composer 渲染
this.composer.render();
}
}
// 启动应用
new PostProcessingDemo();
javascript
// RenderPass - 将场景渲染到渲染目标
const renderPass = new RenderPass(scene, camera);
// MaskPass - 用于遮罩操作
const maskPass = new MaskPass(scene, camera);
// ClearPass - 清除渲染目标
const clearPass = new ClearPass();
javascript
// 辉光效果
import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass.js';
const bloomPass = new UnrealBloomPass(resolution, strength, radius, threshold);
// 胶片效果
import { FilmPass } from 'three/examples/jsm/postprocessing/FilmPass.js';
const filmPass = new FilmPass(noiseIntensity, scanlineIntensity, scanlineCount, grayscale);
// 故障效果
import { GlitchPass } from 'three/examples/jsm/postprocessing/GlitchPass.js';
const glitchPass = new GlitchPass();
javascript
// 创建自定义着色器
const CustomShader = {
uniforms: {
"tDiffuse": { value: null },
"uTime": { value: 0.0 },
"uStrength": { value: 0.5 }
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform sampler2D tDiffuse;
uniform float uTime;
uniform float uStrength;
varying vec2 vUv;
void main() {
vec2 uv = vUv;
// 添加波纹效果
uv.x += sin(uv.y * 10.0 + uTime) * 0.01 * uStrength;
vec4 color = texture2D(tDiffuse, uv);
gl_FragColor = color;
}
`
};
// 创建自定义着色器通道
const customPass = new ShaderPass(CustomShader);
customPass.uniforms.uStrength.value = 0.3;
javascript
// 降低分辨率提升性能
const composer = new EffectComposer(renderer);
composer.setSize(window.innerWidth / 2, window.innerHeight / 2);
// 选择性启用效果
bloomPass.enabled = true; // 或 false 来临时禁用
// 使用多采样抗锯齿
const renderer = new THREE.WebGLRenderer({
antialias: true,
powerPreference: "high-performance"
});
javascript
class EffectController {
constructor(composer) {
this.composer = composer;
this.effects = {};
this.initGUI();
}
addEffect(name, pass) {
this.effects[name] = pass;
}
initGUI() {
// 使用 dat.GUI 或 lil-gui 创建控制面板
const gui = new GUI();
// 控制辉光效果
const bloomFolder = gui.addFolder('Bloom');
bloomFolder.add(bloomPass, 'enabled').name('Enabled');
bloomFolder.add(bloomPass, 'strength', 0, 3).name('Strength');
bloomFolder.add(bloomPass, 'radius', 0, 1).name('Radius');
bloomFolder.add(bloomPass, 'threshold', 0, 1).name('Threshold');
bloomFolder.open();
// 控制胶片效果
const filmFolder = gui.addFolder('Film');
filmFolder.add(filmPass, 'enabled').name('Enabled');
filmFolder.add(filmPass.uniforms.nIntensity, 'value', 0, 1).name('Noise');
filmFolder.open();
}
}
javascript
// 创建额外的渲染目标用于特殊效果
const rtTexture = new THREE.WebGLRenderTarget(
window.innerWidth,
window.innerHeight,
{
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat
}
);
// 在自定义着色器中使用
const customPass = new ShaderPass(CustomShader);
customPass.uniforms.tDiffuse.value = rtTexture.texture;
javascript
// 正确的通道顺序
composer.addPass(renderPass); // 1. 基础渲染
composer.addPass(bloomPass); // 2. 辉光效果
composer.addPass(colorCorrection); // 3. 颜色校正
composer.addPass(outputPass); // 4. 输出(必须设置 renderToScreen = true)
减少通道数量
降低分辨率
禁用不需要的效果
使用更简单的着色器
javascript
// 清理资源
function dispose() {
composer.dispose();
renderTarget.dispose();
// 清理所有通道
passes.forEach(pass => {
if (pass.dispose) pass.dispose();
});
}
javascript
// 角色受伤时的红色闪屏效果
const hurtEffect = new ShaderPass({
uniforms: {
tDiffuse: { value: null },
uHurt: { value: 0.0 }
},
vertexShader: `...`,
fragmentShader: `
uniform sampler2D tDiffuse;
uniform float uHurt;
varying vec2 vUv;
void main() {
vec4 color = texture2D(tDiffuse, vUv);
// 添加红色叠加
color.rgb = mix(color.rgb, vec3(1.0, 0.0, 0.0), uHurt * 0.5);
gl_FragColor = color;
}
`
});
// 触发受伤效果
function triggerHurtEffect() {
hurtEffect.uniforms.uHurt.value = 1.0;
// 渐隐效果
const fadeOut = setInterval(() => {
hurtEffect.uniforms.uHurt.value -= 0.1;
if (hurtEffect.uniforms.uHurt.value <= 0) {
clearInterval(fadeOut);
}
}, 100);
}
javascript
// 卡通渲染效果组合
composer.addPass(renderPass);
composer.addPass(outlinePass); // 边缘描边
composer.addPass(toonShaderPass); // 卡通着色
composer.addPass(halftonePass); // 半色调效果
composer.addPass(outputPass);
EffectComposer 的工作流程可以概括为:
初始化 - 创建渲染器、场景、相机
创建 Composer - 基于渲染器创建 EffectComposer
添加通道 - 按顺序添加各种效果通道
设置输出 - 确保最后一个通道设置 renderToScreen = true
渲染循环 - 使用 composer.render() 替代 renderer.render()
掌握 EffectComposer 可以让你为 Three.js 应用添加丰富的视觉效果,从简单的颜色调整到复杂的多重特效组合,极大提升视觉体验。