Для записи видео с Three.js необходимо корректно настроить сцену,
камеру и рендерер. В стандартной схеме используется
WebGLRenderer с указанием canvas, который
будет использоваться для вывода и последующей записи.
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
Ключевой момент:
preserveDrawingBuffer: true — этот
параметр необходим для того, чтобы содержимое канваса оставалось
доступным для MediaRecorder после каждого кадра.
Three.js поддерживает анимацию через функцию
requestAnimationFrame. Для записи важно, чтобы каждый кадр
рендерился синхронно с MediaRecorder:
function animate() {
requestAnimationFrame(animate);
// Простейшая анимация
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
Сцена может содержать любые объекты: геометрию, материалы, свет и тени. Например, добавление куба:
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 5, 5);
scene.add(light);
camera.position.z = 5;
Для записи видео используется поток из канваса
методом captureStream(). Поток передается конструктору
MediaRecorder:
const canvasStream = renderer.domElement.captureStream(60); // 60 FPS
const options = { mimeType: 'video/webm; codecs=vp9' };
const mediaRecorder = new MediaRecorder(canvasStream, options);
Параметр 60 задает частоту кадров. Поддерживаемые
MIME-типы зависят от браузера: video/webm; codecs=vp9,
video/webm; codecs=vp8 или video/mp4.
MediaRecorder работает асинхронно и генерирует данные через события
dataavailable:
const recordedChunks = [];
mediaRecorder.ondataavaila ble = function(event) {
if (event.data.size > 0) {
recordedChunks.push(event.data);
}
};
mediaRecorder.ons top = function() {
const blob = new Blob(recordedChunks, { type: 'video/webm' });
const url = URL.createObjectURL(blob);
// Создание ссылки для скачивания
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = 'threejs_animation.webm';
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(url);
};
Важно: данные собираются постепенно, поэтому
recordedChunks необходимо аккумулировать, чтобы при
завершении записи сформировать полноценный файл.
MediaRecorder предоставляет методы start(),
pause(), resume() и stop() для
управления процессом:
mediaRecorder.start(); // Начало записи
setTimeout(() => {
mediaRecorder.stop(); // Остановка через 5 секунд
}, 5000);
Можно синхронизировать остановку записи с завершением анимации или любым событием в приложении.
Для плавной записи рекомендуется:
captureStream(60)).preserveDrawingBuffer, иначе MediaRecorder
может получать пустые кадры.Для сложных сцен можно рендерить кадры вручную и вызывать
ctx.drawImage на отдельный OffscreenCanvas, но
в большинстве случаев стандартного рендерера достаточно.
MediaRecorder поддерживает
videoBitsPerSecond для управления качеством:const mediaRecorder = new MediaRecorder(canvasStream, {
mimeType: 'video/webm; codecs=vp9',
videoBitsPerSecond: 5_000_000 // 5 Мбит/с
});
vp8 и
vp9 подходят для веба, h264 доступен не во
всех браузерах.const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const geometry = new THREE.TorusKnotGeometry(1, 0.4, 128, 32);
const material = new THREE.MeshStandardMaterial({ color: 0xff6347, metalness: 0.5, roughness: 0.1 });
const torusKnot = new THREE.Mesh(geometry, material);
scene.add(torusKnot);
const light = new THREE.PointLight(0xffffff, 1);
light.position.set(10, 10, 10);
scene.add(light);
camera.position.z = 5;
function animate() {
requestAnimationFrame(animate);
torusKnot.rotation.x += 0.01;
torusKnot.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
const stream = renderer.domElement.captureStream(60);
const recorder = new MediaRecorder(stream, { mimeType: 'video/webm; codecs=vp9', videoBitsPerSecond: 5_000_000 });
const chunks = [];
recorder.ondataavaila ble = e => { if (e.data.size > 0) chunks.push(e.data); };
recorder.ons top = () => {
const blob = new Blob(chunks, { type: 'video/webm' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'torusKnot.webm';
a.click();
URL.revokeObjectURL(url);
};
recorder.start();
setTimeout(() => recorder.stop(), 10000);
Этот пример демонстрирует полную цепочку: создание сцены, анимация объекта, захват канваса, запись и сохранение видео.