三.JS 光线投射性能

THREE .JS raycasting performance

我正在尝试沿着一个方向 运行ge:

找到从一个点到大型复杂网格的最近距离
 for (var zDown in verticalDistances) {
    var myIntersect = {};  
   for (var theta = Math.PI / 2 - 0.5; theta < Math.PI / 2 + 0.5; theta += 0.3) {
                var rayDirection = new THREE.Vector3(
                    Math.cos(theta),
                    Math.sin(theta),
                    0
                ).transformDirection(object.matrixWorld);
                 //  console.log(rayDirection);

                _raycaster.set(verticalDistances[zDown].minFacePoint, rayDirection, 0, 50);
                //  console.time('raycast: ');
                var intersect = _raycaster.intersectObject(planeBufferMesh);
                //   console.timeEnd('raycast: '); // this is huge!!! ~ 2,300 ms

                //   console.log(_raycaster);
                //    console.log(intersect);
                if (intersect.length == 0) continue;
                if ((!('distance' in myIntersect)) || myIntersect.distance > intersect[0].distance) {
                    myIntersect.distance = intersect[0].distance;
                    myIntersect.point = intersect[0].point.clone();
                }
            }
// do stuff
}

我将鼠标悬停在同一表面上获得了很好的效果,但是在执行此循环时,光线投射每次投射需要超过 2 秒。我唯一能想到的是 DoubleSide Material 的 BackSide 慢了一吨?

我还注意到,当我 space 离开我的 verticalDistances[zDown].minFacePoint 时,光线投射开始加速 (500ms /cast)。因此,随着 verticalDistances[i].minFacePoint 和 verticalDistances[i+1].minFacePoint 之间的距离增加,光线投射器执行得更快。

我会走使用八叉树的路线,但鼠标悬停事件在完全相同的 planeBuffer 上运行得非常好。这是 Material 问题的一个方面吗?这可以通过加载 2 个指向相反方向的 FrontSide 网格来解决吗?

谢谢!!!!

编辑:这不是前后问题。我 运行 我的光线投射到平面缓冲区几何形状的正面和背面,具有相同的点结果。实例来了。

编辑 2:工作示例 here。性能比原始情况好一点,但仍然太慢。我需要实时移动气缸。我可以通过找到某些东西来优化一点,但鼠标悬停是即时的。当您查看控制台时间时,前两个(500 毫秒)是我获得的所有结果的结果。

编辑 3:添加了鼠标悬停事件,其执行与其他光线投射器相同。不过,我没有在我在此示例中获得的工作代码中获得结果。我获得的所有光线投射结果与我在 500 毫秒左右的样本中获得的前 1 或 2 个结果相同。如果我能将它降低到 200 毫秒,我就可以瞄准我正在寻找的项目,并减少光线投射。我完全愿意接受有关更好方法的建议。八叉树是要走的路吗?

raycast: : 467.27001953125ms
raycast: : 443.830810546875ms

编辑 4:@pailhead 这是我的计划。 1.找到最近的网格顶点到平面上的点。我可以在 x/y 方向扫描顶点,然后计算最小距离。 2.一旦我有了那个最近的顶点,我就知​​道我最近的点必须在包含该顶点的面上。因此,我将使用 object.mesh.index.array 找到具有该顶点的所有面,并计算指向每个面的平面。在与网格相交并且至少根据最大距离剔除点时,似乎光线投射应该比全扫描更聪明一点? @WestLangley 有什么建议吗?

编辑 5: @pailhead 谢谢你的帮助。它赞赏。我真的简化了我的 example(<200 行,有更多评论); raycaster 是否检查每张脸?在构造函数中指定的集合光线投射 运行ge 中挑选面孔并进行面对点计算要快得多。这不可能遍历每张脸以进行光线投射。在查看源代码并检查八叉树之后,今晚我将编写自己的 PlaneBufferGeometry 光线投射函数。我认为如果我们在 raycaster 构造函数中有一个 运行ge,则在忽略 z 的情况下拉出该 运行ge 中的平面缓冲区顶点。然后只需对这些进行光线投射或进行点到平面计算。我想我可以从该边界圆创建一个 "mini" 表面,然后对其进行光线投射。但是最大距离(手动使用 "far")不会影响 raycaster 的速度这一事实让我想知道它针对 planeBuffer 几何形状优化了多少。仅供参考,您的 300k 循环在 jsfiddle 上约为 3 毫秒。

编辑 6:看起来所有网格在光线投射函数中都被同等对待。这意味着它不会智能地寻找平面缓冲区几何的区域。查看 mesh.js 第 266 行,我们遍历整个索引数组。我想对于一个普通的网格,你不知道哪些面在哪里,因为它是一个 TIN,但是 planeBuffer 真的可以使用边界 box/sphere 规则,因为你的 x/y 是已知的顺序位置,只有 Z 是未知的.最后编辑,答案将在下一个

仅供参考:对于最大速度,您可以使用数学。无需使用光线投射。 https://brilliant.org/wiki/3d-coordinate-geometry-equation-of-a-plane/

解决的最大问题是根据顶点索引过滤掉 planeBufferGeometry 的面。使用 planeBufferGeometry,您可以找到一个边界球体或矩形,它们将为您提供需要检查的面。它们在索引数组中按 x/y 排序,以便过滤掉许多面孔。我在索引数组中做了左下角位置的 indexOf 和右上角位置的 lastIndexOf 。光线投射检查每一张脸

我也放弃了寻找到物体每个面的距离,而是使用沿着物体中心的垂直路径。这减少了所需的光线投射。

最后,我对自己的脸进行了遍历,并在每张脸上使用了 traingle.closestPointToPoint() 函数。

最终每个点到表面计算(单个光线投射)大约 10 毫秒,每个对象(10 个垂直切片)到表面大约 100 毫秒。在优化之前,我看到每次光线投射 2.5 秒,每个对象超过 25 秒。