我有一个复杂的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不是一个选项,那么你应该可以将场景绘制到一个framebuffer,在这个框架缓冲区里,你附加你自己的纹理来代替正常的z缓冲区.有一个扩展使用适当的深度纹理(more details here),但是在那里是不可能的,您总是可以回退到使用输出每个像素深度的片段着色器绘制场景.
然后可以在深度纹理上使用gl.ReadPixels().再次,请注意GPU-> cpu传输的延迟,这总是很重要.
说完所有这一切,根据你的DOM对象的外观,将DOM对象渲染成一个纹理可以更加容易和快捷,并使用四边形作为3D场景的一部分绘制纹理.