Использование instanced mesh

Instanced Mesh — это метод оптимизации рендеринга большого количества однотипных объектов в 3D-сцене. В отличие от создания множества отдельных сущностей <a-entity> с одинаковой геометрией и материалом, instanced mesh позволяет GPU обрабатывать все экземпляры за один вызов, значительно снижая нагрузку на CPU и увеличивая производительность.

В A-Frame instanced mesh реализуется через компонент instanced-mesh, который использует возможности Three.js THREE.InstancedMesh. Основная идея заключается в том, что создается одна геометрия и один материал, а все экземпляры рендерятся с разными матрицами трансформации.

<a-scene>
  <a-entity id="tree" instanced-mesh="geometry: box; material: color: green; count: 100"></a-entity>
</a-scene>

В этом примере создается 100 экземпляров кубов с зеленым материалом. Ключевые параметры компонента:

  • geometry — тип геометрии (box, sphere, cylinder, или пользовательская).
  • material — свойства материала (color, metalness, roughness и т.д.).
  • count — количество экземпляров.

Настройка позиции, вращения и масштаба

Каждому экземпляру можно задать собственную позицию, поворот и масштаб через массивы данных:

const el = document.querySelector('#tree');
const positions = [];
const rotations = [];
const scales = [];

for (let i = 0; i < 100; i++) {
  positions.push({x: Math.random()*50-25, y: 0, z: Math.random()*50-25});
  rotations.push({x: 0, y: Math.random()*360, z: 0});
  scales.push({x: 1, y: 1 + Math.random()*2, z: 1});
}

el.setAttribute('instanced-mesh', {positions, rotations, scales});
  • Позиции (positions) — массив объектов с координатами {x, y, z}.
  • Вращения (rotations) — массив объектов {x, y, z} в градусах.
  • Масштабы (scales) — массив объектов {x, y, z}.

Instanced Mesh автоматически применяет эти трансформации при рендеринге, не создавая отдельные сущности в DOM.


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

Можно использовать кастомные модели, загруженные через <a-asset-item> и gltf-model. Для instanced mesh это требует создания THREE.BufferGeometry:

AFRAME.registerComponent('instanced-trees', {
  schema: {
    src: {type: 'model'},
    count: {type: 'int', default: 50}
  },
  init() {
    const loader = new THREE.GLTFLoader();
    loader.load(this.data.src, (gltf) => {
      const geometry = gltf.scene.children[0].geometry;
      const material = gltf.scene.children[0].material;
      const mesh = new THREE.InstancedMesh(geometry, material, this.data.count);

      const dummy = new THREE.Object3D();
      for (let i = 0; i < this.data.count; i++) {
        dummy.position.set(Math.random()*50-25, 0, Math.random()*50-25);
        dummy.rotation.y = Math.random()*Math.PI*2;
        dummy.scale.set(1, 1 + Math.random(), 1);
        dummy.updateMatrix();
        mesh.setMatrixAt(i, dummy.matrix);
      }

      this.el.object3D.add(mesh);
    });
  }
});

Этот подход позволяет создавать тысячи экземпляров сложных моделей с минимальной нагрузкой на сцену.


Динамическое обновление экземпляров

Instanced Mesh поддерживает динамическое изменение трансформаций после создания:

const mesh = el.getObject3D('mesh');
const dummy = new THREE.Object3D();

dummy.position.set(0, 5, 0);
dummy.rotation.y = Math.PI / 4;
dummy.updateMatrix();
mesh.setMatrixAt(0, dummy.matrix);
mesh.instanceMatrix.needsUpdate = true;
  • setMatrixAt(index, matrix) — обновляет трансформацию конкретного экземпляра.
  • instanceMatrix.needsUpdate = true — сигнализирует GPU, что матрицы изменились.

Это позволяет реализовать анимацию и интерактивные эффекты без создания новых объектов.


Оптимизация и ограничения

Преимущества instanced mesh:

  • Снижение количества draw calls.
  • Значительно меньше объектов в DOM.
  • Возможность рендерить тысячи экземпляров на слабых устройствах.

Ограничения:

  • Все экземпляры используют один материал. Для разных материалов требуется отдельный instanced mesh.
  • Невозможна привязка событий A-Frame (click, mouseenter) к отдельным экземплярам напрямую. Для интерактивности приходится использовать raycasting на кастомные объекты.
  • Сложности с анимацией скелета или морфингом, так как instanced mesh работает только с статической геометрией.

Примеры применения

  • Лесные сцены — тысячи деревьев, травы, камней.
  • Городские ландшафты — одинаковые здания, столбы, фонари.
  • Частицы и эффекты — снежинки, дождевые капли, пылинки.
  • Игровые объекты — однотипные NPC или враги, спрайты в 3D.

Использование instanced mesh в сочетании с LOD (уровнями детализации) и динамическим рендерингом позволяет создавать реалистичные и масштабные 3D-сцены, оставаясь в пределах производительности браузера.


Интеграция с A-Frame экосистемой

Instanced Mesh полностью совместим с другими компонентами A-Frame, включая animation, shader и light. Для пользовательских шейдеров можно передавать uniform-параметры каждому экземпляру через instanced attributes, что расширяет возможности визуальных эффектов.

Использование instanced mesh является ключевым инструментом для разработки сложных, оптимизированных VR и WebXR сцен на платформе A-Frame.