Радиовещание THREE.js очень медленное против одиночного> 500k поли (граней) объекта, пересечение линии с глобусом - PullRequest
0 голосов
/ 26 февраля 2019

В моем проекте игрок прогуливается по земному шару.Глобус - это не просто сфера, у него есть горы и долины, поэтому мне нужно, чтобы игроки изменили свою позицию.Для этого я делаю луч луча с позиции игрока на один объект (глобус) и получаю точку, в которой они пересекаются, и соответственно меняю позицию игрока.Я использую только лучевое вещание, когда игрок движется, а не на каждом кадре.

Для сложного объекта это занимает вечность.Для объекта с ~ 1 м полисом (гранями) (сфера сегментов 1024x512) требуется ~ 200 мс.Отвечает ли радиовещание каждому лицу?

Существует ли традиционный быстрый способ достичь этого в ТРИ, например, какая-то структура ускорения (октри? Bvh? - tbh из моих поисков в Google, кажется, я не нашел такоговещь, включенная в ТРИ), или какой-то другой метод мышления "из коробки" (без приведения лучей)?

        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.log(t2-t1);

Заранее спасибо

Ответы [ 3 ]

0 голосов
/ 28 февраля 2019

Я думаю, вы должны предварительно визуализировать карту высот вашего земного шара в текстуру, предполагая, что ваш ландшафт не является динамическим.Считайте все это в типизированном массиве, а затем всякий раз, когда ваш игрок перемещается, вам нужно только спроецировать ее координаты в эту текстуру, запросить ее, сместить и умножить, и вы должны получить то, что вам нужно за O (1) времени.

Вам решать, как создать эту карту высот.На самом деле, если у вас есть ухабистый глобус, то вам, вероятно, следует начать с карты высот в первую очередь и использовать ее в своем вершинном шейдере для визуализации глобуса (при этом входная сфера будет идеально гладкой).Затем вы можете использовать ту же карту высот, чтобы запросить у игрока Z .

0 голосов
/ 01 марта 2019

Не используйте Three.js Raycaster.

Рассмотрим Ray.js , который предлагает function intersectTriangle(a, b, c, backfaceCulling, target)

Предлагаемые оптимизации:

  1. Если игрок начинает с некоторых известных позиций ⇒Вы должны знать его начальную высоту, - не нужно делать лучевую передачу (или просто делать одноразовое медленное пересечение с полной сеткой)

  2. если игрок движется маленькими шагами ⇒ следующий лучевой эфир будет наиболее вероятным пересекается с тем же лицом, что и раньше.

Оптимизация # 1 - запомните предыдущее лицо и сначала передайте его в эфир.

если игрок не прыгает ⇒ следующий raycast будет наиболее вероятно пересечет смежную грань с лицом, где был игрок.

Оптимизация # 2 - создать кеш, чтобы по идентификатору лица вы могли получить соседние лица за O (1) раз.

Этот кеш может быть загружен из файла, если ваша планета не сгенерирована в реальном времени.


Так что, используя мой подход к каждому ходу, вы выполняете O (1) операцию чтения изкеш и райкаст 1-6 лиц.

Win!

0 голосов
/ 28 февраля 2019

Для сложного объекта это занимает вечность.Для объекта с ~ 1 м полисом (гранями) (сфера сегментов 1024x512) требуется ~ 200 мс.Приводит ли лучевое вещание к каждому лицу?

Из коробки THREE.js проверяет каждый треугольник при выполнении лучевого вещания по сетке, и в ТРИ нет встроенных ускоряющих структур.

Я работал с другими над пакетом 3-mesh-bvh ( github , npm ), чтобы помочь решить эту проблему, которая может помочь вамвстать на скорости, которые вы ищете.Вот как это можно использовать:

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 и т. Д.).И еще есть некоторая оптимизация памяти, которую можно было бы сделать, но есть несколько настраиваемых опций, которые помогут настроить это.

Мне будет интересно услышать, как это работает для вас!Не стесняйтесь оставлять отзывы в вопросах, как улучшить пакет, а также.Надеюсь, это поможет!

...