в моем проекте у меня есть игрок, который ходит по земному шару. Земной шар — это не просто сфера, в нем есть горы и долины, поэтому мне нужно, чтобы положение игроков по оси z менялось. Для этого я направляю один луч из положения игрока на один объект (земной шар) и получаю точку, в которой они пересекаются, и соответствующим образом меняю положение игроков. Я делаю рейкастинг только тогда, когда игрок движется, а не на каждом кадре.
Для сложного объекта это занимает вечность. Для объекта с ~1 м полигонов (граней) (сфера сегментов 1024x512) требуется ~200 мс. Использует ли raycasting каждое лицо?
Есть ли традиционный быстрый способ добиться этого в THREE, например, какая-то структура ускорения (octree? bvh? -- tbh из моих поисков в Google я, кажется, не нашел такой вещи, включенной в THREE) или какое-то другое мышление из метод коробки (без луча)?
var dir = g_Game.earthPosition.clone();
var startPoint = g_Game.cubePlayer.position.clone();
var directionVector = dir.sub(startPoint.multiplyScalar(10));
g_Game.raycaster.set(startPoint, directionVector.clone().normalize());
var t1 = new Date().getTime();
var rayIntersects = g_Game.raycaster.intersectObject(g_Game.earth, true);
if (rayIntersects[0]) {
var dist = rayIntersects[0].point.distanceTo(g_Game.earthPosition);
dist = Math.round(dist * 100 + Number.EPSILON) / 100;
g_Player.DistanceFromCenter = dist + 5;
}
var t2 = new Date().getTime();
console.info(t2-t1);
заранее спасибо



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


For a complex object it takes forever. It takes ~200ms for an object with ~1m polys (faces) (1024x512 segments sphere). Does raycasting cast against every single face ?
Из коробки THREE.js делает проверяет каждый треугольник при выполнении raycast против сетки, и в THREE нет встроенных структур ускорения.
Я работал с другими над пакетом three-mesh-bvh (гитхаб, нпм), чтобы помочь решить эту проблему, тем не менее, что может помочь вам достичь скорости, которую вы ищете. Вот как вы можете его использовать:
import * as THREE from 'three';
import { MeshBVH, acceleratedRaycast } from 'three-mesh-bvh';
THREE.Mesh.prototype.raycast = acceleratedRaycast;
// ... initialize the scene...
globeMesh.geometry.boundsTree = new MeshBVH(globeMesh.geometry);
// ... initialize raycaster...
// Optional. Improves the performance of the raycast
// if you only need the first collision
raycaster.firstHitOnly = true;
const intersects = raycaster.intersectObject(globeMesh, true);
// do something with the intersections
В README упоминаются некоторые предостережения, поэтому имейте их в виду (индекс сетки изменен, поддерживается только неанимированная BufferGeometry и т. д.). И есть еще некоторая оптимизация памяти, которую можно выполнить, но есть некоторые настраиваемые параметры, которые помогут это настроить.
Мне будет интересно услышать, как это работает для вас! Не стесняйтесь оставлять отзывы в вопросах о том, как улучшить пакет, а также. Надеюсь, это поможет!
Я думаю, вам следует предварительно отрендерить карта высот вашего земного шара в текстуру, предполагая, что ваш ландшафт не динамичен. Считайте все это в типизированный массив, а затем всякий раз, когда ваш игрок перемещается, вам нужно только обратно спроецировать его координаты в эту текстуру, запросить ее, сместить и умножить, и вы должны получить то, что вам нужно за время O (1).
Вам решать, как создать эту карту высот. На самом деле, если у вас есть неровный земной шар, то вам, вероятно, следует начать с карты высот в первую очередь и использовать ее в своем вершинном шейдере для рендеринга земного шара (с идеально гладкой входной сферой). Затем вы можете использовать ту же карту высот для запроса Z игрока.
Не используйте three.js Raycaster.
Рассмотрим Ray.js, который предлагает function intersectTriangle(a, b, c, backfaceCulling, target)
Предлагаемые оптимизации:
Если игрок начинает с некоторых известных позиций ⇒ вы должны знать его начальную высоту, − нет необходимости в рейкасте (или просто сделайте один раз медленное пересечение с полной сеткой)
если игрок движется маленькими шагами ⇒ следующий рейкаст будет вероятно пересекать ту же грань, что и раньше.
Оптимизация №1 — запомнить предыдущее лицо и сначала выполнить его рейкаст.
Оптимизация №2 — создайте кеш, чтобы с учетом идентификатора лица вы могли получить соседние лица за время O (1).
Этот кеш можно загрузить из файла, если ваша планета не генерируется в реальном времени.
Таким образом, с моим подходом на каждом шаге вы выполняете O (1) операцию чтения из кеша и raycast 1-6 лиц.
Выиграть!
карта высот будет либо неточной, либо огромной (или и то, и другое)