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

时间:2019-02-26 11:43:08

标签: javascript math three.js geometry

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

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

是否有传统的快速方法可以在三个时间内实现这一目标,例如某种加速结构(八叉树?bvh?-来自我的google搜索的tbh,我似乎没有发现这样的东西包含在三个中)或其他一些思考方式-开箱即用(无射线投射)方法?

        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 :(得分:7)

请勿使用three.js Raycaster。

考虑提供function intersectTriangle(a, b, c, backfaceCulling, target)的{​​{3}}

建议的优化

  1. 如果玩家从某个已知位置开始⇒您必须知道他的初始身高,−无需进行射线投射(或只进行一次全网格慢速交点)

  2. 如果玩家以较小的步伐移动⇒下一次光线投射将最有可能与同一张脸相交。

优化#1 -记住前一张脸,然后进行光线投射。

  1. 如果玩家没有跳动,⇒下一个光线投射将最有可能与相邻的面孔相交到玩家之前的面孔。

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

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


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

赢!

答案 1 :(得分:6)

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

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

答案 2 :(得分:4)

  

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

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

尽管如此,我已经与其他人一起研究了三目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

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

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