Создание пользовательской геометрии: AFRAME.registerGeometry

AFRAME.registerGeometry предоставляет возможность создавать собственные геометрические объекты в A-Frame, расширяя стандартный набор примитивов (box, sphere, cylinder и т.д.). Этот механизм позволяет полностью контролировать вершины, индексы, нормали и UV-координаты, что открывает путь к сложным кастомным формам и интерактивным 3D-моделям.

Регистрация пользовательской геометрии

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

AFRAME.registerGeometry('имя-геометрии', {
  schema: {
    параметр1: {type: 'число', default: значение},
    параметр2: {type: 'число', default: значение}
  },
  init: function (data) {
    const geometry = new THREE.BufferGeometry();

    // Создание вершин
    const vertices = new Float32Array([
      // x, y, z координаты
    ]);

    // Определение индексов
    const indices = [
      // порядок соединения вершин в треугольники
    ];

    geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
    geometry.setIndex(indices);

    // Вычисление нормалей
    geometry.computeVertexNormals();

    this.geometry = geometry;
  }
});
  • schema — описывает параметры геометрии, доступные для конфигурации через атрибуты A-Frame. Например, размер стороны куба, радиус сферы или количество сегментов.
  • init — метод, который вызывается при создании геометрии и должен вернуть объект THREE.BufferGeometry через this.geometry.

Работа с вершинами и индексами

В THREE.BufferGeometry вершины (vertices) представляют собой массив чисел, где каждая тройка соответствует координатам точки (x, y, z). Индексы (indices) определяют порядок соединения этих точек в треугольники. Этот подход позволяет:

  • Создавать несимметричные и сложные формы.
  • Минимизировать дублирование вершин, используя один набор индексов для нескольких треугольников.
  • Контролировать нормали для корректного освещения.

Пример создания простой пирамиды:

AFRAME.registerGeometry('pyramid', {
  schema: {
    height: {type: 'number', default: 1},
    base: {type: 'number', default: 1}
  },
  init: function (data) {
    const geometry = new THREE.BufferGeometry();
    const h = data.height / 2;
    const b = data.base / 2;

    const vertices = new Float32Array([
      -b, -h, -b,  b, -h, -b,  b, -h, b,  -b, -h, b,  // база
      0, h, 0  // вершина
    ]);

    const indices = [
      0,1,4, 1,2,4, 2,3,4, 3,0,4,  // боковые грани
      0,1,2, 0,2,3   // основание
    ];

    geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
    geometry.setIndex(indices);
    geometry.computeVertexNormals();

    this.geometry = geometry;
  }
});

Использование кастомной геометрии в сцене

После регистрации геометрии она доступна как новый примитив в <a-entity>:

<a-scene>
  <a-entity geometry="primitive: pyramid; base: 2; height: 3" material="color: orange"></a-entity>
</a-scene>
  • Атрибут geometry ссылается на имя зарегистрированной геометрии.
  • Параметры base и height автоматически привязываются к схеме, определённой в AFRAME.registerGeometry.

Динамическая модификация геометрии

С помощью схемы и метода update можно изменять геометрию на лету. Например, изменение высоты пирамиды в зависимости от события:

AFRAME.registerGeometry('dynamic-pyramid', {
  schema: { height: {type: 'number', default: 1} },
  init: function(data) {
    this.createGeometry(data.height);
  },
  update: function(data) {
    this.createGeometry(data.height);
  },
  createGeometry: function(height) {
    const geometry = new THREE.BufferGeometry();
    const b = 1;
    const h = height / 2;

    const vertices = new Float32Array([
      -b, -h, -b,  b, -h, -b,  b, -h, b,  -b, -h, b,
      0, h, 0
    ]);

    const indices = [0,1,4, 1,2,4, 2,3,4, 3,0,4, 0,1,2, 0,2,3];

    geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
    geometry.setIndex(indices);
    geometry.computeVertexNormals();

    this.geometry = geometry;
  }
});

Использование в сцене с анимацией:

<a-entity geometry="primitive: dynamic-pyramid; height: 1" animation="property: geometry.height; to: 5; loop: true; dir: alternate; dur: 2000" material="color: teal"></a-entity>

Расширенные возможности

  • UV-карты: можно добавлять UV-координаты для корректного наложения текстур.
  • Custom Attributes: через BufferAttribute можно задавать цвета вершин (color), веса, смещения и другие пользовательские данные.
  • Интеграция с Three.js: зарегистрированная геометрия полностью совместима с объектами Three.js, что позволяет использовать шейдеры, буферные материалы и эффекты постобработки.

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

  1. Для сложных объектов лучше использовать индексы и минимизировать дублирование вершин.
  2. Всегда вычислять нормали (computeVertexNormals) для правильного освещения.
  3. Использовать схемы для параметризации, чтобы геометрия оставалась гибкой и изменяемой в A-Frame.
  4. Для анимации и интерактивных эффектов рекомендуется использовать метод update для пересоздания геометрии при изменении параметров.

Эти принципы позволяют создавать любые формы, от простых полигональных объектов до динамически изменяемых 3D-моделей, полностью интегрированных в экосистему A-Frame и Three.js.