EffectComposer: цепочка эффектов

EffectComposer — это ключевой инструмент в Three.js для постобработки сцены, позволяющий объединять несколько визуальных эффектов в единую цепочку. Вместо того чтобы напрямую рендерить сцену в WebGLRenderer, EffectComposer создаёт промежуточные буферы, которые затем обрабатываются passes. Это открывает возможности для создания сложных эффектов, таких как размытие, свечение, цветокоррекция, глубина резкости и множество других визуальных фильтров.

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 composer = new EffectComposer(renderer);

Главная задача EffectComposer — упорядочивание passes и контроль их последовательности. Каждый pass может модифицировать изображение, полученное от предыдущего, создавая сложные визуальные эффекты без изменения самой сцены.


RenderPass

RenderPass является основным элементом цепочки и отвечает за рендеринг сцены в буфер. Обычно он добавляется первым:

const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);

Ключевые параметры:

  • scene — сцена, которую необходимо отрендерить.
  • camera — камера для проекции сцены.
  • overrideMaterial (опционально) — позволяет заменить материалы всей сцены для специальных эффектов, например для создания масок.
  • clearColor и clearAlpha — настройка очистки буфера перед рендерингом.

ShaderPass

ShaderPass используется для применения пользовательских или встроенных шейдеров к изображению. Это основной инструмент для создания фильтров.

import { SepiaShader } from 'three/examples/jsm/shaders/SepiaShader.js';

const sepiaPass = new ShaderPass(SepiaShader);
composer.addPass(sepiaPass);

Особенности ShaderPass:

  • uniforms — позволяет передавать параметры в шейдер.
  • renderToScreen — определяет, должен ли этот pass выводить изображение на экран. Обычно только последний pass в цепочке имеет renderToScreen = true.

Встроенные эффекты Three.js

Three.js поставляется с набором готовых эффектов:

  1. BloomPass — создаёт эффект свечения ярких объектов.
  2. FilmPass — добавляет шум и линии сканирования, имитируя старый фильм.
  3. GlitchPass — имитация цифровых артефактов и «глитчей».
  4. OutlinePass — обводка объектов контурами, полезно для выделения.

Каждый из этих pass может быть добавлен в EffectComposer в любой последовательности, но порядок имеет критическое значение, так как эффекты накапливаются друг на друге.


Последовательность рендеринга

Эффекты обрабатываются строго по порядку добавления в composer:

  1. RenderPass — рендер сцены в буфер.
  2. ShaderPass или любой постэффект — модификация изображения.
  3. Финальный ShaderPass с renderToScreen = true — вывод результата на экран.

Пример цепочки:

composer.addPass(renderPass);
composer.addPass(bloomPass);
composer.addPass(filmPass);
filmPass.renderToScreen = true;

В этом случае сцена сначала рендерится, затем добавляется свечение, и в конце накладывается «кинематографический» фильтр.


Маскирование и ClearMaskPass

MaskPass и ClearMaskPass позволяют ограничить действие эффектов определёнными объектами сцены. Это полезно для локальных эффектов, например, свечения только на одном объекте:

import { MaskPass, ClearMaskPass } from 'three/examples/jsm/postprocessing/MaskPass.js';

const maskPass = new MaskPass(scene, camera);
const clearMaskPass = new ClearMaskPass();

composer.addPass(maskPass);
composer.addPass(bloomPass);
composer.addPass(clearMaskPass);
  • MaskPass активирует маску, определяя область применения следующего эффекта.
  • ClearMaskPass снимает маску, возвращая глобальный рендеринг.

Производительность

Использование EffectComposer увеличивает нагрузку на GPU, так как каждый pass требует отдельного рендеринга в текстуру. Рекомендации для оптимизации:

  • Минимизировать количество passes.
  • Использовать меньшие разрешения для промежуточных буферов (composer.setSize(width/2, height/2)).
  • Применять эффекты selectively, только там, где это действительно необходимо.

Обновление composer в цикле рендеринга

Цепочка эффектов обновляется в основном цикле вместо прямого renderer.render:

function animate() {
    requestAnimationFrame(animate);
    // Обновление сцены, анимации объектов
    composer.render();
}
animate();

Это гарантирует, что все эффекты применяются последовательно и корректно.


Настройка буферов и multi-sampling

EffectComposer использует WebGLRenderTarget для хранения промежуточного изображения. Для повышения качества можно использовать multi-sampling, уменьшение артефактов размытия и сглаживания краёв:

const renderTarget = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight, {
    samples: 4
});
const composer = new EffectComposer(renderer, renderTarget);

Ключевой момент: поддержка multi-sampling зависит от устройства и браузера, поэтому необходимо проверять доступность через renderer.capabilities.isWebGL2.


Кастомные шейдеры и расширения

Создание собственного эффекта требует написания шейдера с uniforms, vertexShader и fragmentShader. Пример простого эффекта инверсии цвета:

const InvertShader = {
    uniforms: { tDiffuse: { value: null } },
    vertexShader: `
        varying vec2 vUv;
        void main() {
            vUv = uv;
            gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
        }
    `,
    fragmentShader: `
        uniform sampler2D tDiffuse;
        varying vec2 vUv;
        void main() {
            vec4 color = texture2D(tDiffuse, vUv);
            gl_FragColor = vec4(vec3(1.0) - color.rgb, color.a);
        }
    `
};
const invertPass = new ShaderPass(InvertShader);
composer.addPass(invertPass);
invertPass.renderToScreen = true;

Такой подход обеспечивает полную свободу в создании визуальных эффектов.


Итоговая структура

Эффективная цепочка эффектов обычно строится так:

  1. RenderPass — основной рендер сцены.
  2. Маски (MaskPass, ClearMaskPass) — локализация эффектов.
  3. ShaderPass/готовые эффекты — фильтры, свечение, размытие.
  4. Финальный pass с renderToScreen = true — вывод на экран.

Эта структура обеспечивает гибкость, модульность и позволяет комбинировать любые эффекты для достижения требуемой визуальной стилистики.