如何快速查找某个点是否在复杂场景中被遮挡?

Frx*_*rem 11 javascript raytracing webgl three.js

我有一个复杂的3D场景,我需要在3D坐标的基础上显示HTML元素.(我只是将div标签叠加在顶部并用CSS定位.)但是,当3D坐标被模型遮挡时(或者以另一种方式表达时,我也需要部分隐藏它(例如,使其透明))它在相机中不可见).这些模型可能有数十万个面孔,我需要一种方法来确定它是否模糊得足以让它每秒运行多次.

目前,我正在使用Three.js的内置光线跟踪器,其代码如下:

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

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

是否有更好,更有效的方法来查明场景中的模型是否可见或模糊点?

Gio*_*Gio 3

我不知道有什么真正快速的方法,但你确实有一些选择。我对 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);
}
Run Code Online (Sandbox Code Playgroud)

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

如果 WebGl 2.0 不是一个选项,那么您可能应该将场景绘制到帧缓冲区,在其中附加您自己的纹理来代替普通的 z 缓冲区。有一个扩展可以使用适当的深度纹理(更多详细信息请参见此处),但是如果不可能,您始终可以使用输出每个像素深度的片段着色器来绘制场景。

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

话虽如此,根据您的 DOM 对象的外观,将 DOM 对象渲染为纹理并使用四边形作为 3d 场景的一部分绘制该纹理可能会更容易、更快捷。