BufferGeometry: внутреннее устройство

BufferGeometry является основой для всех геометрических объектов в Three.js и представляет собой эффективный способ хранения вершин, нормалей, цветов и других атрибутов. В отличие от устаревшего Geometry, BufferGeometry работает напрямую с массивами данных, что позволяет значительно снизить нагрузку на CPU и повысить производительность рендеринга.

Ключевые аспекты:

  • Данные хранятся в виде BufferAttribute или InterleavedBufferAttribute.
  • Атрибуты представляют собой массивы чисел (Float32Array, Uint16Array и т.д.).
  • Каждый атрибут связан с конкретной семантикой: position, normal, color, uv и др.
  • Геометрия может быть индексированной для повторного использования вершин через index.

Атрибуты и BufferAttribute

Атрибуты хранятся в объекте attributes, где ключ — имя атрибута, а значение — объект BufferAttribute. Основные атрибуты:

  • position – координаты вершин (x, y, z).
  • normal – нормали для освещения.
  • color – цвета вершин.
  • uv – координаты текстур.
  • index – порядок соединения вершин для формирования треугольников.

Пример создания простого атрибута:

const vertices = new Float32Array([
    0, 0, 0,
    1, 0, 0,
    0, 1, 0
]);
const positionAttribute = new THREE.BufferAttribute(vertices, 3);
geometry.setAttribute('position', positionAttribute);

Здесь каждый набор из трёх чисел соответствует одной вершине. Второй параметр указывает размерность (3 для 3D координат).

Индексированная геометрия

Использование индексов позволяет избежать дублирования вершин, особенно в сложных моделях. Атрибут index хранит массив индексов вершин:

const indices = new Uint16Array([0, 1, 2]);
geometry.setIndex(new THREE.BufferAttribute(indices, 1));

Индексированная геометрия уменьшает объём памяти и ускоряет рендеринг, так как GPU повторно использует уже переданные вершины.

InterleavedBuffer и InterleavedBufferAttribute

Для оптимизации больших массивов данных используется InterleavedBuffer, где разные атрибуты хранятся в одном массиве:

const array = new Float32Array([
    0, 0, 0, 1, 0, 0, // vertex1: position(x,y,z) + color(r,g,b)
    1, 0, 0, 0, 1, 0, // vertex2
]);
const interleavedBuffer = new THREE.InterleavedBuffer(array, 6); // 6 значений на вершину
geometry.setAttribute('position', new THREE.InterleavedBufferAttribute(interleavedBuffer, 3, 0));
geometry.setAttribute('color', new THREE.InterleavedBufferAttribute(interleavedBuffer, 3, 3));

Преимущества: сокращение числа отдельных массивов, уменьшение overhead при передаче данных на GPU.

Методы модификации BufferGeometry

  • setAttribute(name, attribute) – добавляет или заменяет атрибут.
  • getAttribute(name) – возвращает атрибут по имени.
  • deleteAttribute(name) – удаляет атрибут.
  • setIndex(index) – задаёт индексы вершин.
  • computeVertexNormals() – автоматически вычисляет нормали на основе позиции вершин.
  • applyMatrix4(matrix) – применяет матрицу трансформации ко всем вершинам.
  • translate(x, y, z), rotateX(angle), rotateY(angle), rotateZ(angle), scale(x, y, z) – упрощённые методы трансформации.

Геометрия и буферы GPU

BufferGeometry напрямую отображается в Vertex Buffer Object (VBO) на GPU. Каждое обновление атрибута требует уведомления GPU через needsUpdate:

geometry.attributes.position.needsUpdate = true;

Для динамических объектов рекомендуется использовать:

positionAttribute.setUsage(THREE.DynamicDrawUsage);

Это указывает WebGL, что буфер будет часто изменяться, оптимизируя пересылку данных.

Оптимизация и производительность

  1. Минимизация количества атрибутов – хранить только необходимые данные.
  2. Индексирование – уменьшает количество вершин.
  3. InterleavedBuffer – снижает overhead передачи данных.
  4. DynamicDrawUsage – для динамических объектов.
  5. mergeBufferGeometries() – объединение геометрий в одну для сокращения draw call.

Практические примеры

Простая треугольная сетка:

const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
    -1, -1, 0,
     1, -1, 0,
     0,  1, 0
]);
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
geometry.computeVertexNormals();

const material = new THREE.MeshStandardMaterial({ color: 0xff0000 });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

Смешение нескольких атрибутов:

const positions = new Float32Array([...]);
const colors = new Float32Array([...]);
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
material.vertexColors = true;

Такой подход позволяет визуализировать сложные эффекты, управляя цветами вершин напрямую, без текстур.


BufferGeometry обеспечивает основу для любой сложной 3D-сцены в Three.js. Понимание структуры атрибутов, индексов и работы с GPU критично для оптимизации производительности и создания высокоэффективных визуализаций.