Генерация скриншота из canvas

Three.js использует объект WebGLRenderer, который привязывается к HTML-элементу <canvas>. Для генерации скриншота важно заранее правильно настроить рендерер и размеры canvas.

import * as THREE from 'three';

// Создание сцены
const scene = new THREE.Scene();

// Настройка камеры
const camera = new THREE.PerspectiveCamera(
    75, 
    window.innerWidth / window.innerHeight, 
    0.1, 
    1000
);
camera.position.z = 5;

// Создание рендерера и привязка к canvas
const renderer = new THREE.WebGLRenderer({ preserveDrawingBuffer: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

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


Добавление объектов и освещения

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

// Геометрия и материал
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshStandardMaterial({ color: 0x0077ff });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// Освещение
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);

const pointLight = new THREE.PointLight(0xffffff, 1);
pointLight.position.set(5, 5, 5);
scene.add(pointLight);

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


Анимация сцены

Для динамичного изображения часто используют цикл анимации с вращением объектов:

function animate() {
    requestAnimationFrame(animate);
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    renderer.render(scene, camera);
}

animate();

Генерация скриншота

После настройки сцены и рендерера получение изображения осуществляется через метод toDataURL() у canvas.

function takeScreenshot() {
    const dataURL = renderer.domElement.toDataURL('image/png');
    downloadImage(dataURL, 'screenshot.png');
}

function downloadImage(data, filename) {
    const link = document.createElement('a');
    link.href = data;
    link.download = filename;
    link.click();
}

Ключевой момент: формат image/png сохраняет прозрачность и обеспечивает высокое качество. Для JPEG можно использовать 'image/jpeg'.


Масштабирование и разрешение скриншота

Чтобы получить изображение в высоком разрешении, рендерер можно масштабировать с помощью setSize:

function takeHighResScreenshot(multiplier = 2) {
    const originalWidth = renderer.domElement.width;
    const originalHeight = renderer.domElement.height;

    renderer.setSize(originalWidth * multiplier, originalHeight * multiplier);
    renderer.render(scene, camera);

    const dataURL = renderer.domElement.toDataURL('image/png');

    renderer.setSize(originalWidth, originalHeight); // возвращаем исходный размер
    downloadImage(dataURL, `screenshot_${multiplier}x.png`);
}

Выделение: увеличение размеров canvas увеличивает качество скриншота без потери деталей. Важно восстановить исходные размеры, чтобы не нарушить отображение на странице.


Скрытый рендеринг для генерации изображений без отображения

Можно создавать отдельный рендерер и canvas, которые не прикрепляются к DOM. Это удобно для серверного или скрытого рендеринга:

const offscreenRenderer = new THREE.WebGLRenderer({ preserveDrawingBuffer: true });
offscreenRenderer.setSize(1920, 1080);

offscreenRenderer.render(scene, camera);
const hiddenScreenshot = offscreenRenderer.domElement.toDataURL('image/png');

Выделение: такой подход позволяет генерировать скриншоты без видимого canvas, что полезно для генерации миниатюр или серверного рендеринга.


Настройка качества изображения

Three.js позволяет управлять antialiasing для сглаживания краев:

const renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true });

Для получения более гладких скриншотов при масштабировании часто используют комбинацию увеличения разрешения canvas и включенного antialiasing.


Сохранение изображений с прозрачным фоном

Если сцена должна иметь прозрачный фон, необходимо:

const renderer = new THREE.WebGLRenderer({ alpha: true, preserveDrawingBuffer: true });
renderer.setClearColor(0x000000, 0); // полностью прозрачный

При генерации PNG изображения прозрачные области будут сохранены.


Совмещение с GUI для управления скриншотами

Для удобства можно интегрировать GUI (например, dat.GUI) для выбора разрешения и формата скриншота:

import GUI from 'dat.gui';

const gui = new GUI();
const params = {
    resolution: 2,
    capture: () => takeHighResScreenshot(params.resolution)
};

gui.add(params, 'resolution', 1, 5, 1);
gui.add(params, 'capture');

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