我有一个复杂的3D场景,需要基于3D坐标在其上方显示HTML元素。 (我只是在顶部叠加了div标记,并使用CSS对其进行了定位。)但是,当3D坐标被模型遮盖(或用其他方式表达)时,我还需要部分隐藏(例如,使其透明)当它在相机中不可见时)。这些模型可能有成千上万的面孔,我需要一种方法来找出它是否足够快以至于每秒可以运行多次。

当前,我正在使用Three.js的内置raytracer,其代码如下:

// pos   = vector with (normalized) x, y coordinates on canvas
// dir   = vector from camera to target point

const raycaster = new THREE.Raycaster();
const d = dir.length(); // distance to point
let intersects = false;
raycaster.setFromCamera(pos, camera);
const intersections = raycaster.intersectObject(modelObject, true);
if (intersections.length > 0 && intersections[0].distance < d)
    intersects = true;

// if ray intersects at a point closer than d, then the target point is obscured
// otherwise it is visible

但是,在这些复杂的模型上,这非常慢(帧速率从50 fps下降到8 fps)。我一直在寻找更好的方法来执行此操作,但到目前为止,在这种情况下,我还没有找到任何有效的方法。

是否有更好,更有效的方法来确定场景中的模型是否可见或遮盖了某个点?

最佳答案

我不知道有什么真正的快捷方法,但是您确实有一些选择。我对three.js不够了解,无法告诉您如何使用该库,但是一般来说谈论WebGL ...

如果可以使用WebGL 2.0,则可以使用遮挡查询。归结为

var query = gl.createQuery();
gl.beginQuery(gl.ANY_SAMPLES_PASSED, query);
// ... draw a small quad at the specified 3d position ...
gl.endQuery(gl.ANY_SAMPLES_PASSED);
// some time later, typically a few frames later (after a fraction of a second)
if (gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE))
{
     gl.getQueryParameter(query, gl.QUERY_RESULT);
}

但是请注意,查询结果仅在几帧后可用。

如果不选择WebGl 2.0,则您可能应该将场景绘制到帧缓冲区,在其中附加您自己的纹理以代替普通的z缓冲区使用。扩展了使用正确的深度纹理(more details here)的功能,但是在不可能的情况下,您总是可以使用片段着色器输出场景,该片段着色器输出每个像素的深度。

然后,您可以在深度纹理上使用gl.ReadPixels()。同样,请注意GPU-> CPU传输的延迟,这总是很重要的。

综上所述,根据您的DOM对象的外观,将DOM对象渲染为纹理并使用四边形作为3d场景的一部分来绘制该纹理可能更加容易和快捷。

关于javascript - 如何快速查找复杂场景中的点是否被遮挡?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36745711/

10-14 15:13