THREE.js对单个> 500k多边形(面)对象,与地球的线相交的光线投射非常慢

Mir*_*ror 7 javascript math geometry three.js

在我的项目中,我有一个球员环游世界。地球不仅是一个球体,而且还有山脉和山谷,因此我需要玩家的z位置进行更改。为此,我从玩家的位置向单个物体(地球)发出光线,然后得到它们相交的点并相应地更改玩家的位置。我只是在播放器移动时发出光线,而不是在每一帧上发出光线。

对于复杂的对象,它需要永远的时间。具有约1m个多边形(面)(1024x512分段球面)的对象大约需要200毫秒。光线投射会投射到每个人的脸上吗?

有没有传统的快速方法可以在三个过程中实现这一目标,例如某种加速结构(八叉树?盒装(无射线投射)方法?

        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);
Run Code Online (Sandbox Code Playgroud)

先感谢您

Ale*_*lov 8

不要使用three.js Raycaster。

考虑提供以下内容的Ray.jsfunction intersectTriangle(a, b, c, backfaceCulling, target)

建议的优化:

  1. 玩家是否从某些已知位置开始?您必须知道他的初始身高吗?无需进行光线投射(或仅进行一次全网格慢速交集)

  2. 玩家是否以小步移动?下一次光线投射很可能与以前相交。

优化#1?记住前一张脸,并先进行光线投射。

  1. 如果玩家不跳?下一个光线投射很可能将相邻的面孔与播放器之前的面孔相交。

优化#2?建立一个缓存,以便在给定一个面部idx的情况下,您可以在O(1)时间内检索相邻的面部。

如果您的星球不是实时生成的,则可以从文件中加载此缓存。


因此,按照我的方法,您可以从缓存和raycast 1-6面执行O(1)读取操作。

赢得!


skr*_*rat 7

我认为您应该将地球的高度图预先渲染为纹理,前提是您的地形不是动态的。将所有内容读取到一个类型化的数组中,然后只要播放器移动,您只需将其坐标反向投影到该纹理中,对其进行查询,偏移和相乘即可,您应该在O(1)时间内得到所需的内容。

如何生成该高度图取决于您。实际上,如果您有一个凹凸不平的地球,那么您可能应该首先从高度图开始,然后在顶点着色器中使用它来渲染地球(输入球完美平滑)。然后你可以使用相同的高度地图来查询玩家的ž


Gar*_*son 6

对于复杂的对象,它需要永远的时间。具有约1m个多边形(面)(1024x512分段球面)的对象大约需要200毫秒。光线投射会投射到每个人的脸上吗?

开箱即用THREE.js 在对网格执行光线投射时检查每个三角形,并且THREE.js 没有内置加速结构。

不过,我已经与其他人一起研究了3个网眼bvh软件包(githubnpm),以帮助解决此问题,这可能有助于您达到所需的速度。使用方法如下:

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
Run Code Online (Sandbox Code Playgroud)

自述文件中提到了一些注意事项,因此请记住这些注意事项(修改了网格索引,仅支持非动画化的BufferGeometry等)。还有一些内存优化可以完成,但是有一些可调整的选项可以帮助您进行调整。

我很想听听这对您的运作方式!也可以就如何改进该软件包的问题发表反馈意见。希望有帮助!