Оптимизация: BVH и three-mesh-bvh

При работе с большими сценами в Three.js критически важна оптимизация, особенно когда сцена содержит тысячи объектов или сложные геометрии. Одним из самых эффективных подходов является использование BVH (Bounding Volume Hierarchy) — иерархической структуры ограничивающих объёмов для ускорения операций с мешами, таких как raycasting, пересечения и столкновения.


Принципы работы BVH

Bounding Volume Hierarchy (BVH) — это структура данных, которая рекурсивно делит геометрию на узлы, каждый из которых ограничен простым объёмом (обычно AABB — Axis-Aligned Bounding Box).

Основные преимущества использования BVH:

  • Снижение количества проверок. Вместо перебора всех треугольников проверяется только пересечение с узлами.
  • Ускорение raycasting. Лучи проверяются сначала на крупные узлы, а затем на дочерние, уменьшая число операций на сотни и тысячи раз.
  • Эффективная работа с динамическими мешами. Узлы BVH могут обновляться при изменении геометрии, сохраняя производительность.

Принцип построения BVH включает:

  1. Разбиение геометрии на группы треугольников.
  2. Оборачивание каждой группы в минимальный ограничивающий объём.
  3. Рекурсивное объединение узлов в дерево, где каждый родительский узел охватывает дочерние.

Three-mesh-bvh

three-mesh-bvh — сторонняя библиотека для Three.js, реализующая BVH для мешей. Она позволяет ускорять:

  • Raycasting для больших и сложных объектов.
  • Boolean-операции и пересечения.
  • Physics-вычисления, такие как детекция столкновений.

Установка:

npm install three-mesh-bvh

Импорт в проект:

import { MeshBVH, acceleratedRaycast } from 'three-mesh-bvh';
import * as THREE from 'three';

Интеграция BVH с мешами Three.js

Для ускорения raycasting у меша необходимо заменить стандартный метод raycast на оптимизированный:

// Подключение ускоренного raycast
THREE.Mesh.prototype.raycast = acceleratedRaycast;

// Создание BVH для геометрии
const geometry = new THREE.BufferGeometry();
// ... заполняем geometry вершинами и индексами
geometry.computeBoundsTree = MeshBVH.prototype.build; 
geometry.computeBoundsTree();

// Применение к мешу
const mesh = new THREE.Mesh(geometry, material);

После этого любые вызовы raycaster.intersectObject(mesh) будут выполняться значительно быстрее, особенно на больших геометриях.


Настройка параметров BVH

three-mesh-bvh предоставляет опции для настройки производительности:

  • maxDepth — максимальная глубина дерева. Увеличение глубины ускоряет точное raycasting, но требует больше памяти.
  • maxLeafTris — максимальное количество треугольников в листовом узле. Уменьшение значения повышает точность, увеличивает время построения.
  • lazyGeneration — отложенное построение BVH, полезно для динамически загружаемых мешей.

Пример:

const bvh = new MeshBVH(geometry, {
    maxLeafTris: 20,
    lazyGeneration: false
});
geometry.boundsTree = bvh;

Работа с динамическими объектами

Для объектов, геометрия которых изменяется в процессе анимации, можно использовать методы refit или update:

// После изменения вершин
geometry.attributes.position.needsUpdate = true;

// Перестройка BVH
geometry.boundsTree.refit();

Метод refit обновляет ограничивающие объёмы без полной перестройки дерева, что позволяет сохранять производительность при изменении формы объекта.


Применение в raycasting

С BVH raycasting становится логарифмическим по количеству треугольников, а не линейным. Пример использования:

const raycaster = new THREE.Raycaster();
raycaster.set(origin, direction);

const intersects = raycaster.intersectObject(mesh, true);
intersects.forEach(hit => {
    console.log(hit.point, hit.faceIndex);
});

На больших мешах (десятки тысяч треугольников) ускорение может достигать 50–100 раз по сравнению с обычным raycasting.


Дополнительные возможности three-mesh-bvh

  • Mesh slicing: разрезание меша на части для сложных эффектов.
  • Raycast с учетом непрозрачности: можно исключить внутренние или прозрачные треугольники.
  • Boolean-операции: пересечение, вычитание и объединение мешей с BVH.

Использование BVH и three-mesh-bvh в Three.js является ключевым инструментом для оптимизации сложных сцен. Эти методы позволяют эффективно работать с высокополигональными моделями, ускоряют raycasting и детекцию столкновений, делая интерактивные приложения плавными и отзывчивыми даже при больших объемах геометрии.