Адаптация к размеру окна браузера

В Three.js сцена создаётся с использованием объекта THREE.WebGLRenderer, который отрисовывает графику на элементе <canvas>. Размер этого канваса напрямую влияет на качество изображения и соотношение сторон сцены. Для корректного отображения необходимо синхронизировать размеры рендерера с размерами окна браузера и обновлять камеру при изменении этих размеров.

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

Ключевой момент: renderer.setSize(width, height) задаёт внутренние размеры канваса, что напрямую влияет на разрешение и качество отрисовки.

Настройка камеры для адаптивности

Наиболее часто используется перспективная камера THREE.PerspectiveCamera. Она требует указания угла обзора (fov), соотношения сторон (aspect), а также ближней и дальней плоскостей обрезки (near, far). Соотношение сторон камеры должно соответствовать соотношению сторон рендерера:

const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
camera.position.z = 5;

При изменении размеров окна необходимо обновлять aspect камеры и вызывать camera.updateProjectionMatrix(), чтобы предотвратить искажения изображения.

window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
});

Использование window.devicePixelRatio

Для поддержки дисплеев с высокой плотностью пикселей (Retina и аналогичных) важно учитывать window.devicePixelRatio. Это позволяет избежать размытия и повышает качество рендеринга.

renderer.setPixelRatio(window.devicePixelRatio);

Следует применять это в комбинации с setSize, чтобы канвас правильно масштабировался:

renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);

Поддержка разных режимов полноэкранного отображения

Для приложений с динамическим переходом в полноэкранный режим рекомендуется использовать событие fullscreenchange:

document.addEventListener('fullscreenchange', () => {
    const width = window.innerWidth;
    const height = window.innerHeight;
    renderer.setSize(width, height);
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
});

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

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

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

let resizeTimeout;
window.addEventListener('resize', () => {
    clearTimeout(resizeTimeout);
    resizeTimeout = setTimeout(() => {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }, 100);
});

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

Адаптация элементов сцены под размер окна

Некоторые объекты сцены и элементы интерфейса (например, 2D-спрайты или текстовые метки) требуют динамического пересчёта своих размеров и позиций в зависимости от размеров окна. Для этого можно использовать относительные единицы:

sprite.scale.set(window.innerWidth * 0.1, window.innerHeight * 0.1, 1);
sprite.position.set(window.innerWidth * 0.5, window.innerHeight * 0.5, 0);

При изменении окна необходимо обновлять такие параметры в обработчике resize, чтобы элементы оставались пропорциональными.

Интеграция с библиотеками управления камерой

Если используется THREE.OrbitControls или аналогичные средства управления камерой, важно вызывать controls.update() после изменения размеров камеры, чтобы интерфейс корректно реагировал на новые параметры сцены:

window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
    controls.update();
});

Практические рекомендации

  • Всегда использовать renderer.setPixelRatio(window.devicePixelRatio) для высокой четкости.
  • Обновлять camera.aspect и вызывать camera.updateProjectionMatrix() при каждом изменении размеров окна.
  • Для сложных сцен использовать дебаунсинг событий resize, чтобы снизить нагрузку на GPU.
  • Проверять корректность отображения интерфейсных элементов и спрайтов при масштабировании.

Адаптация к размеру окна — ключевой аспект при создании интерактивных 3D-приложений, обеспечивающий правильное отображение, высокое качество и отзывчивость интерфейса.