В Three.js система постобработки реализована через EffectComposer, который управляет последовательностью рендер-пассов. Каждый пасс — это отдельный шаг обработки изображения. ShaderPass позволяет применять пользовательские шейдеры к сцене после её рендеринга, создавая эффекты вроде размытия, цветокоррекции или искажений.
ShaderPass представляет собой обёртку вокруг
материала типа ShaderMaterial, где задаются шейдеры вершин
(vertexShader) и фрагментов (fragmentShader),
а также униформы (uniforms), через которые
можно передавать данные в GPU.
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';
// Основная сцена и камера
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);
// Постобработка
const composer = new EffectComposer(renderer);
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
Любой шейдерный пасс строится по стандартной схеме:
Пример простого эффекта размытия:
const BlurShader = {
uniforms: {
'tDiffuse': { value: null },
'resolution': { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
'blurAmount': { value: 1.0 }
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform sampler2D tDiffuse;
uniform vec2 resolution;
uniform float blurAmount;
varying vec2 vUv;
void main() {
vec4 color = vec4(0.0);
float total = 0.0;
for (float x = -4.0; x <= 4.0; x++) {
for (float y = -4.0; y <= 4.0; y++) {
vec2 offset = vec2(x, y) * blurAmount / resolution;
color += texture2D(tDiffuse, vUv + offset);
total += 1.0;
}
}
gl_FragColor = color / total;
}
`
};
const blurPass = new ShaderPass(new THREE.ShaderMaterial({
uniforms: BlurShader.uniforms,
vertexShader: BlurShader.vertexShader,
fragmentShader: BlurShader.fragmentShader
}));
composer.addPass(blurPass);
Униформы можно динамически обновлять каждый кадр. Это позволяет анимировать эффекты, например:
function animate(time) {
requestAnimationFrame(animate);
blurPass.material.uniforms['blurAmount'].value = 1.0 + 0.5 * Math.sin(time * 0.001);
composer.render();
}
animate();
EffectComposer поддерживает последовательное
добавление нескольких пассов. Последние пассы можно пометить свойством
renderToScreen = true, чтобы их результат выводился на
экран:
const colorShiftPass = new ShaderPass(ColorShiftShader);
colorShiftPass.renderToScreen = true;
composer.addPass(colorShiftPass);
Важно помнить, что все пассы до последнего передают результат в текстуру, а финальный пасс рисуется на экран.
THREE.WebGLRenderTarget) для промежуточных пассов снижает
нагрузку GPU.THREE.UniformsUtils.clone() для
повторного использования без глобального конфликта униформ.vUv и шумовые текстуры для создания волновых
эффектов.THREE.DepthTexture.ShaderPass легко комбинируется с другими эффектами Three.js, включая
OutlinePass, BloomPass или пользовательские
шейдеры с RawShaderMaterial. Главное — корректно передавать
tDiffuse и другие текстуры в униформы, а также следить за
порядком пассов, так как они влияют на итоговый результат.
Эффективное использование ShaderPass открывает возможности создавать уникальные визуальные эффекты, выходящие за пределы стандартного рендеринга Three.js.