Как обновлять сущности «Вердж3Д» с помощью «Ява Скрипта»
Как использовать «Ява Скрипт» для обновления различных сущностей «Вердж3Д», таких как объекты, материалы, текстуры, камеры или буферы геометрии.
Объекты
Все объекты по умолчанию автоматически обновляют свои матрицы, если они были добавлены на сцену с помощью
const object = new v3d.Object3D();
scene.add(object);
или если они являются дочерними объектами другого объекта, который был добавлен в сцену:
const object1 = new v3d.Object3D();
const object2 = new v3d.Object3D();
object1.add(object2);
scene.add(object1); // матрицы объектов object1 и object2 обновятся автоматически
Однако, если вы знаете, что объект будет статичным, вы можете отключить эту функцию и обновлять матрицу преобразования по необходимости.
object.matrixAutoUpdate = false;
object.updateMatrix();
Материалы
Все юниформы можно свободно менять (например, цвета, текстуры, альфа-канал и т.д.),— их значения отправляются в шейдер каждый кадр.
Также параметры, связанные с состоянием WebGL, могут изменяться в любое время (depthTest, blending, polygonOffset и т.д.).
Следующие свойства не могут быть легко изменены во время выполнения:
- нодовый граф нодовых материалов
- количество и типы юниформов
- наличие или отсутствие
- текстур
- тумана
- вертесных цветов
- скиннинга
- морфинга
- карты теней
- альфа теста
Их изменение потребует создания новой шейдерной программы. Чтобы это сделать, выполните:
material.needsUpdate = true
Для нодовых материалов также потребуется вызвать:
material.updateNodeGraph()
Имейте в виду, что это может быть довольно медленно и вызвать рывки в частоте кадров (особенно на Виндоус, поскольку компиляция шейдеров в ДиректИкс происходит медленнее, чем в ОпенГЛ).
Для более плавного восприятия вы можете в некоторой степени эмулировать изменения этих характеристик, используя «фиктивные» значения, такие как освещение нулевой интенсивности, белые текстуры или туман нулевой плотности.
Текстуры
Текстуры изображений, холста, видео и данных должны устанавливать следующий флаг, если они изменяются:
texture.needsUpdate = true;
Рендер таргеты обновляются автоматически.
Камеры
Положение и цель камеры обновляются автоматически. Если вам необходимо изменить:
- fov, aspect (для перспективных камер)
- left, right, top, bottom (для ортографических камер)
- viewportFit
- near
- far
то вам нужно будет заново вычислить матрицу проекции:
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
BufferGeometry
Объекты BufferGeometry хранят информацию (такую как позиции вершин, индексы граней, нормали, цвета, UV развертки и любые пользовательские атрибуты) в буферах — то есть, в типизированных массивах. Это делает их в целом быстрее стандартной Геометрии, ценой того, что с ними несколько сложнее работать.
Что касается обновления BufferGeometry, самое важное, что нужно понять, это то, что вы не можете изменять размер буферов (это очень затратно, и эквивалентно созданию новой геометрии). Однако вы можете обновить содержимое буферов.
Это означает, что если вы знаете, что атрибут вашего BufferGeometry будет расти, например, количество вершин, вы должны предварительно выделить достаточно большой буфер, чтобы вместить все новые вершины, которые могут быть созданы. Конечно, это также означает, что существует максимальный размер вашего BufferGeometry - не существует способа создать BufferGeometry, который может эффективно расширяться бесконечно.
Мы будем использовать пример линии, которая удлиняется во время рендеринга. Мы выделим место в буфере для 500 вершин, но сначала нарисуем только две, используя BufferGeometry.drawRange.
const MAX_POINTS = 500;
// геометрия
const geometry = new v3d.BufferGeometry();
// атрибуты
const positions = new Float32Array(MAX_POINTS * 3); // 3 координаты на вертекс
geometry.addAttribute('position', new v3d.BufferAttribute(positions, 3));
// объём рендеринга
const drawCount = 2; // рисовать только первые 2 вертекса
geometry.setDrawRange(0, drawCount);
// материал
const material = new v3d.LineBasicMaterial({ color: 0xff0000, linewidth: 2 });
// линия
const line = new v3d.Line(geometry, material);
scene.add(line);
Далее мы произвольно добавим точки к линии, используя паттерн, например:
const positions = line.geometry.attributes.position.array;
let x, y, z, index;
x = y = z = index = 0;
for (let i = 0, l = MAX_POINTS; i < l; i++) {
positions[index++] = x;
positions[index++] = y;
positions[index++] = z;
x += (Math.random() - 0.5) * 30;
y += (Math.random() - 0.5) * 30;
z += (Math.random() - 0.5) * 30;
}
Если вы хотите изменить количество точек отображаемых после первого рендеринга, сделайте следующее:
line.geometry.setDrawRange(0, newValue);
Если вы хотите изменить значения данных о позиции после первого рендеринга, вам необходимо установить параметр needsUpdate следующим образом:
line.geometry.attributes.position.needsUpdate = true; // требуется после первого рендеринга
Если вы измените значения данных о положении после первоначального рендеринга, вам может потребоваться пересчитать охватывающие объекты.
line.geometry.computeBoundingBox();
line.geometry.computeBoundingSphere();
Пазлы
Пазлы, работающие с вышеуказанными сущностями (объектами, материалами и т.д.), производят необходимые обновления автоматически.