В Three.js рендеринг сцены строится на последовательном выполнении пассов (passes). Каждый пасс представляет собой отдельный этап обработки сцены, который может включать в себя отрисовку объектов, постобработку эффектов или композитинг нескольких текстур. Понимание порядка выполнения пассов критически важно для оптимизации производительности и правильного отображения визуальных эффектов.
Основной цикл рендеринга в Three.js устроен следующим образом:
Каждый пасс может опираться на результаты предыдущего, поэтому изменение порядка выполнения напрямую влияет на визуальный результат. Например, эффект bloom должен применяться после базового рендеринга, иначе подсветка объектов будет некорректной.
Three.js предоставляет EffectComposer, который позволяет объединять несколько пассов в цепочку и управлять ими:
const composer = new THREE.EffectComposer(renderer);
const renderPass = new THREE.RenderPass(scene, camera);
composer.addPass(renderPass);
const bloomPass = new THREE.UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5, 0.4, 0.85
);
composer.addPass(bloomPass);
composer определяет их
последовательность применения.Важно понимать, что EffectComposer использует промежуточные рендер-таргеты (render targets). Каждый пасс пишет в текстуру, которая затем может использоваться следующими пассами. Это накладывает ограничения на производительность: больше пассов → больше операций чтения/записи в GPU.
Избыточное использование пассов негативно сказывается на FPS. Основные рекомендации:
Пример корректного использования renderToScreen:
bloomPass.renderToScreen = true; // финальный вывод
Если несколько пассов с renderToScreen = true, вывод
будет некорректным, и часть GPU-ресурсов будет потрачена впустую.
При работе с прозрачными объектами важно учитывать порядок
рендеринга. Three.js выполняет сортировку по глубине
(depth sorting) перед рендерингом. Однако при нескольких
пассах с постэффектами:
Использование depthWrite и depthTest в
материалах позволяет контролировать корректное наложение слоев:
material.transparent = true;
material.depthWrite = false;
material.depthTest = true;
Эффективное использование THREE.WebGLRenderTarget
позволяет:
Пример создания render target:
const renderTarget = new THREE.WebGLRenderTarget(
window.innerWidth / 2,
window.innerHeight / 2,
{ minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter }
);
Здесь разрешение уменьшено вдвое, что снижает нагрузку на GPU при постобработке.
При работе с прозрачными объектами и эффектами типа bloom или SSAO рекомендуется использовать два подхода:
Пример использования слоев:
opaqueObjects.layers.set(0);
transparentObjects.layers.set(1);
camera.layers.enable(0);
camera.layers.enable(1);
Это позволяет избежать конфликта глубины и сохранить корректный порядок визуализации.
mask и stencil только при
необходимости.renderToScreen — только у финального
пасса.WebGLRenderTarget для кэширования сложных
сцен.Эти правила позволяют создать сложную визуализацию в Three.js без существенного падения FPS, сохраняя корректный порядок рендеринга и качество постобработки.