Three.js предоставляет мощный инструмент для оптимизации рендеринга большого числа идентичных объектов — InstancedMesh. В отличие от обычных мешей, каждый экземпляр InstancedMesh использует одну и ту же геометрию и материал, но может иметь свои уникальные трансформации и свойства. Это позволяет существенно экономить память и ресурсы GPU при визуализации сцен с тысячами повторяющихся объектов.
InstancedMesh создается с использованием следующего конструктора:
const mesh = new THREE.InstancedMesh(geometry, material, count);
Например:
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const count = 1000;
const instancedMesh = new THREE.InstancedMesh(geometry, material, count);
scene.add(instancedMesh);
Здесь создается 1000 одинаковых кубов с зеленым материалом.
Каждый экземпляр InstancedMesh можно позиционировать, вращать и
масштабировать независимо. Для этого используется объект
THREE.Matrix4 и метод
setMatrixAt(index, matrix):
const dummy = new THREE.Object3D();
for (let i = 0; i < count; i++) {
dummy.position.set(Math.random() * 50 - 25, Math.random() * 50, Math.random() * 50 - 25);
dummy.rotation.set(Math.random() * Math.PI, Math.random() * Math.PI, 0);
dummy.scale.setScalar(Math.random() + 0.5);
dummy.updateMatrix();
instancedMesh.setMatrixAt(i, dummy.matrix);
}
Объяснение:
dummy — вспомогательный объект, который позволяет
удобно вычислять матрицы трансформации.updateMatrix() — пересчитывает внутреннюю матрицу
объекта на основе позиции, вращения и масштаба.setMatrixAt(i, matrix) — задает матрицу для i-го
экземпляра.После изменения матриц нужно обновить буфер на GPU:
instancedMesh.instanceMatrix.needsUpdate = true;
InstancedMesh позволяет задавать индивидуальные цвета для каждого экземпляра, если включить instanceColor. Для этого материал должен поддерживать vertex colors:
const material = new THREE.MeshStandardMaterial({ vertexColors: true });
const colors = [];
for (let i = 0; i < count; i++) {
colors.push(Math.random(), Math.random(), Math.random());
}
const colorAttribute = new THREE.InstancedBufferAttribute(new Float32Array(colors), 3);
instancedMesh.instanceColor = colorAttribute;
Теперь каждый экземпляр может иметь свой уникальный цвет, при этом сохраняя общую геометрию и материал.
InstancedMesh отлично подходит для анимации большого количества объектов. Можно изменять матрицы на каждом кадре:
function animate() {
requestAnimationFrame(animate);
for (let i = 0; i < count; i++) {
dummy.rotation.y += 0.01;
dummy.updateMatrix();
instancedMesh.setMatrixAt(i, dummy.matrix);
}
instancedMesh.instanceMatrix.needsUpdate = true;
renderer.render(scene, camera);
}
animate();
Эффективность здесь достигается за счет того, что GPU обрабатывает все экземпляры одной командой отрисовки, а не каждой меш отдельно.
Использование InstancedMesh значительно увеличивает производительность при рендеринге сцены с повторяющимися объектами и позволяет реализовывать сложные эффекты без нагрузки на CPU.