Babylon.js — мощная библиотека для создания 3D-графики на JavaScript. При работе с современными фреймворками, такими как React и Vue.js, важна правильная организация компонентов и управление жизненным циклом сцены, камер и рендерера.
React ориентирован на декларативное создание интерфейсов, что требует аккуратной интеграции с императивной природой Babylon.js. Основные подходы включают создание отдельного компонента, который управляет сценой.
Создание компонента BabylonScene:
import React, { useRef, useEffect } from 'react';
import * as BABYLON from 'babylonjs';
const BabylonScene = () => {
const canvasRef = useRef(null);
const engineRef = useRef(null);
useEffect(() => {
const canvas = canvasRef.current;
const engine = new BABYLON.Engine(canvas, true);
engineRef.current = engine;
const scene = new BABYLON.Scene(engine);
// Камера и свет
const camera = new BABYLON.ArcRotateCamera(
'camera',
Math.PI / 2,
Math.PI / 4,
10,
new BABYLON.Vector3(0, 0, 0),
scene
);
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight(
'light',
new BABYLON.Vector3(0, 1, 0),
scene
);
// Простейшая геометрия
const sphere = BABYLON.MeshBuilder.CreateSphere(
'sphere',
{ diameter: 2 },
scene
);
engine.runRenderLoop(() => {
scene.render();
});
// Очистка ресурсов
return () => {
scene.dispose();
engine.dispose();
};
}, []);
return <canvas ref={canvasRef} style={{ width: '100%', height: '100%' }} />;
};
export default BabylonScene;
Ключевые моменты при интеграции с React:
useRef для хранения canvas и engine.useEffect с пустым массивом
зависимостей, чтобы инициализация выполнялась один раз.engine.resize().Работа с состоянием React:
Для взаимодействия с UI можно использовать хуки состояния
(useState) и передавать значения внутрь сцены через
наблюдаемые объекты Babylon.js (Observable) или напрямую
обновлять свойства мешей и материалов.
Vue.js использует реактивную систему, которая позволяет связывать данные и элементы DOM. Для интеграции Babylon.js создаются кастомные компоненты или директивы, управляющие рендерингом сцены.
Пример компонента BabylonScene.vue:
<template>
<canvas ref="canvas" style="width: 100%; height: 100%"></canvas>
</template>
<script>
import * as BABYLON from 'babylonjs';
export default {
name: 'BabylonScene',
mounted() {
const canvas = this.$refs.canvas;
const engine = new BABYLON.Engine(canvas, true);
const scene = new BABYLON.Scene(engine);
// Камера и свет
const camera = new BABYLON.ArcRotateCamera(
'camera',
Math.PI / 2,
Math.PI / 4,
10,
new BABYLON.Vector3(0, 0, 0),
scene
);
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight(
'light',
new BABYLON.Vector3(0, 1, 0),
scene
);
const box = BABYLON.MeshBuilder.CreateBox('box', { size: 2 }, scene);
engine.runRenderLoop(() => {
scene.render();
});
window.addEventListener('resize', () => {
engine.resize();
});
this.$once('hook:beforeDestroy', () => {
scene.dispose();
engine.dispose();
});
}
};
</script>
Особенности интеграции с Vue.js:
mounted для инициализации сцены после
рендера DOM.ref.beforeDestroy для
предотвращения утечек памяти.Для сложных приложений полезно использовать централизованные состояния (например, Redux для React или Vuex для Vue.js) для управления 3D-объектами. Это позволяет:
Пример обновления позиции меша через состояние:
// React с useState
const [position, setPosition] = useState({ x: 0, y: 0, z: 0 });
useEffect(() => {
sphere.position.x = position.x;
sphere.position.y = position.y;
sphere.position.z = position.z;
}, [position]);
scene.freezeActiveMeshes() и
scene.freezeMaterials() для статических сцен.Mesh.MergeMeshes) для уменьшения draw
calls.Правильная интеграция Babylon.js с современными фреймворками строится на разделении ответственности: UI и реактивные данные управляются React/Vue, а 3D-сцена — Babylon.js. Жизненный цикл компонентов должен соответствовать жизненному циклу движка, что обеспечивает плавность работы и стабильность приложений с 3D-графикой.