Интеграция с React и Vue.js

Babylon.js — мощная библиотека для создания 3D-графики на JavaScript. При работе с современными фреймворками, такими как React и Vue.js, важна правильная организация компонентов и управление жизненным циклом сцены, камер и рендерера.


Использование Babylon.js с React

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 с пустым массивом зависимостей, чтобы инициализация выполнялась один раз.
  • Корректное уничтожение сцены и движка при размонтировании компонента для предотвращения утечек памяти.
  • Управление размерами canvas с помощью CSS и обработчиков изменения размера окна через engine.resize().

Работа с состоянием React:

Для взаимодействия с UI можно использовать хуки состояния (useState) и передавать значения внутрь сцены через наблюдаемые объекты Babylon.js (Observable) или напрямую обновлять свойства мешей и материалов.


Использование Babylon.js с Vue.js

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.
  • Привязка canvas через ref.
  • Очистка ресурсов в хуке beforeDestroy для предотвращения утечек памяти.
  • Реактивные свойства Vue могут использоваться для управления параметрами объектов сцены, камер и материалов.

Совместное использование состояний и реактивности

Для сложных приложений полезно использовать централизованные состояния (например, Redux для React или Vuex для Vue.js) для управления 3D-объектами. Это позволяет:

  • Синхронизировать параметры сцены с UI.
  • Создавать анимации на основе реактивных данных.
  • Отслеживать события взаимодействия пользователя с 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-графикой.