Raycasting — это метод определения пересечения луча
с объектами сцены, который широко используется для взаимодействия
пользователя с 3D-сценой: выбор объектов мышью, столкновения, навигация
и многое другое. В Three.js класс THREE.Raycaster
обеспечивает удобный API для реализации этих задач.
Для начала создаётся объект луча:
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
mouse хранит координаты курсора в нормализованных
координатах WebGL:
Луч устанавливается через метод setFromCamera:
raycaster.setFromCamera(mouse, camera);
camera — объект камеры
(THREE.PerspectiveCamera или
THREE.OrthographicCamera). После этого
raycaster готов искать пересечения с объектами сцены.
Метод intersectObjects возвращает массив объектов, с
которыми луч пересёкся:
const intersects = raycaster.intersectObjects(scene.children, true);
true) позволяет искать пересечения
рекурсивно, включая дочерние объекты.Каждый элемент массива intersects содержит:
object — объект, с которым произошло пересечение.point — координаты точки пересечения.distance — расстояние от луча до точки
пересечения.face — информация о грани, через которую произошло
пересечение.uv — координаты текстуры в точке пересечения.Raycasting часто применяется для:
Пример использования для подсветки объекта при наведении мыши:
if (intersects.length > 0) {
intersects[0].object.material.color.set(0xff0000);
}
THREE.InstancedMesh позволяет эффективно отображать
тысячи одинаковых объектов с минимальной нагрузкой на GPU, используя
один геометрический буфер и отдельные трансформации для
каждого экземпляра.
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const count = 1000;
const mesh = new THREE.InstancedMesh(geometry, material, count);
scene.add(mesh);
geometry и material общие для всех
экземпляров.count — количество экземпляров.Каждому экземпляру присваивается матрица трансформации:
const dummy = new THREE.Object3D();
for (let i = 0; i < count; i++) {
dummy.position.set(Math.random() * 10, Math.random() * 10, Math.random() * 10);
dummy.rotation.set(Math.random() * Math.PI, Math.random() * Math.PI, Math.random() * Math.PI);
dummy.scale.set(1, 1, 1);
dummy.updateMatrix();
mesh.setMatrixAt(i, dummy.matrix);
}
dummy используется как вспомогательный объект для
генерации матриц.setMatrixAt(i, matrix) задаёт положение, поворот и
масштаб отдельного экземпляра.Если требуется динамическое обновление:
mesh.instanceMatrix.needsUpdate = true;
Это уведомляет Three.js о том, что матрицы экземпляров изменились.
InstancedMesh поддерживает raycasting, но пересечение
возвращает не сам объект, а индекс экземпляра через
instanceId:
const intersects = raycaster.intersectObject(mesh);
if (intersects.length > 0) {
const instanceId = intersects[0].instanceId;
mesh.setColorAt(instanceId, new THREE.Color(0xff0000));
mesh.instanceColor.needsUpdate = true;
}
setColorAt позволяет менять цвет отдельного
экземпляра.instanceColor при
создании материала:material = new THREE.MeshStandardMaterial({ vertexColors: true });
mesh.instanceColor = new THREE.InstancedBufferAttribute(new Float32Array(count * 3), 3);
Использование InstancedMesh значительно уменьшает
количество отдельных draw calls. Для сцен с тысячами одинаковых
объектов:
Mesh на каждую копию создаёт отдельный draw
call.InstancedMesh объединяет их в один draw call, позволяя
GPU рендерить массив объектов быстрее.Raycasting для InstancedMesh работает эффективно, но при
большом количестве экземпляров стоит применять ограничивающие
объёмы (Bounding Box или
Bounding Sphere) для предварительной фильтрации.
Комбинация этих технологий позволяет создавать интерактивные сцены с тысячами объектов и быстрым выбором:
InstancedMesh с большим количеством
объектов.Raycaster определяет пересечения, возвращая индекс
экземпляра.instanceId изменяются цвет, анимация или
другие свойства выбранного объекта.Эта схема позволяет создавать игры, визуализации данных, симуляции частиц и интерактивные панели с минимальной нагрузкой на рендеринг и высокий отклик на взаимодействие.