Несколько камер и сплит-экран

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

Создание и настройка камер

В Three.js обычно используются три типа камер: PerspectiveCamera, OrthographicCamera и CubeCamera. Для сплит-экрана чаще всего применяются перспективные камеры.

const camera1 = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera1.position.set(0, 5, 10);

const camera2 = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera2.position.set(10, 5, 0);
camera2.lookAt(0, 0, 0);

Ключевой момент: каждая камера имеет собственное поле зрения, аспектное соотношение и положение в сцене. Для корректного отображения на экране необходимо правильно задавать aspect при изменении размеров окна.

window.addEventListener('resize', () => {
    camera1.aspect = window.innerWidth / window.innerHeight;
    camera1.updateProjectionMatrix();

    camera2.aspect = window.innerWidth / window.innerHeight;
    camera2.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);
});

Рендеринг нескольких камер

Для отображения нескольких камер на одном экране используется метод рендера с указанием viewport. Это позволяет разделить экран на зоны, каждая из которых отображает сцену с определенной камеры.

function render() {
    renderer.setScissorTest(true);

    // Левая половина экрана
    renderer.setViewport(0, 0, window.innerWidth / 2, window.innerHeight);
    renderer.setScissor(0, 0, window.innerWidth / 2, window.innerHeight);
    renderer.render(scene, camera1);

    // Правая половина экрана
    renderer.setViewport(window.innerWidth / 2, 0, window.innerWidth / 2, window.innerHeight);
    renderer.setScissor(window.innerWidth / 2, 0, window.innerWidth / 2, window.innerHeight);
    renderer.render(scene, camera2);

    renderer.setScissorTest(false);
}

Важно: использование setScissor гарантирует, что каждая камера рендерит только в своей области, предотвращая наложение изображения другой камеры.

Организация сплит-экрана

Сплит-экран можно реализовать различными способами:

  1. Вертикальный сплит – экран делится на левую и правую части.
  2. Горизонтальный сплит – экран делится на верхнюю и нижнюю части.
  3. Сетка камер – экран делится на четыре или более секций для множественных камер.

Пример горизонтального сплита:

// Верхняя половина
renderer.setViewport(0, window.innerHeight / 2, window.innerWidth, window.innerHeight / 2);
renderer.setScissor(0, window.innerHeight / 2, window.innerWidth, window.innerHeight / 2);
renderer.render(scene, camera1);

// Нижняя половина
renderer.setViewport(0, 0, window.innerWidth, window.innerHeight / 2);
renderer.setScissor(0, 0, window.innerWidth, window.innerHeight / 2);
renderer.render(scene, camera2);

Синхронизация камер и взаимодействие

Камеры могут быть независимыми или синхронизированными. Для синхронизации положения или вращения удобно использовать общий контроллер, например OrbitControls:

const controls1 = new THREE.OrbitControls(camera1, renderer.domElement);
const controls2 = new THREE.OrbitControls(camera2, renderer.domElement);

function animate() {
    requestAnimationFrame(animate);

    controls1.update();
    controls2.update();

    render();
}

Для игровых приложений камеры можно привязать к разным игрокам или объектам сцены, обновляя их позиции внутри цикла анимации.

Использование камер с разными эффектами

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

const composer1 = new THREE.EffectComposer(renderer);
const composer2 = new THREE.EffectComposer(renderer);

// Настройка рендер-процессов отдельно для каждой камеры

Производительность и оптимизация

  • Использовать минимальное количество объектов в каждой камере, если видимость ограничена.
  • Выключать ненужные тени и материалы с высоким разрешением для камер, которые не требуют детализации.
  • Обновлять только изменяемые объекты между рендерами камер, чтобы снизить нагрузку на GPU.

Многокамерная система в Three.js с правильной организацией viewport и scissor-тестов обеспечивает гибкий сплит-экран, позволяя создавать интерактивные сцены с несколькими точками зрения и сложными визуальными эффектами.