Three.js предоставляет мощный механизм работы с
BufferGeometry, позволяющий напрямую управлять
вершинами, нормалями, цветами и другими атрибутами. В отличие от старого
Geometry, BufferGeometry хранит данные в
Typed Arrays, что обеспечивает высокую
производительность при рендеринге и обновлении сцены. Динамическое
обновление этих атрибутов необходимо для анимации вершин, изменения
цвета поверхности в реальном времени, создания интерактивных эффектов и
физически основанных симуляций.
Ключевые моменты:
THREE.BufferAttribute или
THREE.Float32BufferAttribute.array атрибута.attribute.needsUpdate = true.Атрибут position отвечает за координаты вершин объекта.
Пример обновления позиции одной вершины:
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
0, 0, 0,
1, 0, 0,
0, 1, 0
]);
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
vertices[0] = 0.5; // Изменение x первой вершины
geometry.attributes.position.needsUpdate = true;
Важно, что индексация массива строго линейная: каждая вершина занимает 3 значения (x, y, z). При работе с большим числом вершин рекомендуется избегать создания новых массивов и изменять существующие данные для оптимизации производительности.
Нормали определяют направление поверхности для освещения. При изменении вершин необходимо пересчитывать нормали:
geometry.computeVertexNormals();
geometry.attributes.normal.needsUpdate = true;
Если геометрия изменяется постепенно (например, в анимации волн),
вызов computeVertexNormals() каждый кадр может быть
дорогостоящим. В таких случаях можно хранить заранее рассчитанные
нормали или использовать шейдеры для динамических вычислений.
Three.js поддерживает вершинные цвета, которые можно динамически менять:
const colors = new Float32Array([
1, 0, 0,
0, 1, 0,
0, 0, 1
]);
geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
colors[0] = 0.5; // Полупрозрачный красный
geometry.attributes.color.needsUpdate = true;
Для использования цветов в материале необходимо включить флаг
vertexColors:
const material = new THREE.MeshStandardMaterial({ vertexColors: true });
BufferAttributeДля анимации часто используют синусоиды или случайные функции:
const time = performance.now() * 0.001;
for (let i = 0; i < vertices.length; i += 3) {
vertices[i + 2] = Math.sin(time + i * 0.1) * 0.5; // Волны по оси Z
}
geometry.attributes.position.needsUpdate = true;
geometry.computeVertexNormals();
Использование Float32Array и прямое изменение значений
позволяет анимировать тысячи вершин с высокой частотой кадров.
Если используется geometry.setIndex(), необходимо
учитывать, что позиции изменяются в
position, а индекс просто указывает, какие вершины
использовать для построения треугольников. Для динамических анимаций
изменяется только position, индекс можно
оставить неизменным.
dynamic: true при
создании атрибута:geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3).setUsage(THREE.DynamicDrawUsage));
computeVertexNormals(). Пересчитывать нормали
только при значительных изменениях.Three.js использует цикл рендера через
requestAnimationFrame. Для динамических геометрий структура
кода обычно такая:
function animate() {
requestAnimationFrame(animate);
// Обновление вершин
updateVertices();
renderer.render(scene, camera);
}
animate();
В функции updateVertices() происходит изменение массива
атрибута, установка needsUpdate = true и, при
необходимости, пересчет нормалей.
Динамическое обновление атрибутов в Three.js является основой для
процедурной анимации, интерактивных эффектов и оптимизированного
рендеринга больших сцен. Гибкая работа с
BufferGeometry и понимание принципов
BufferAttribute позволяет создавать сложные визуальные
эффекты без потери производительности.