查找相机可以在 Three.js 中看到的 object3D - 从每个相机到对象的光线投射
Find which object3D's the camera can see in Three.js - Raycast from each camera to object
我的 Three.js 场景中有一个点网格(object3D 使用 THREE.Points),模型位于网格顶部,如下所示。在代码中,模型被称为 default mesh
并出于性能原因使用合并的几何体:
我正在尝试找出我的透视相机在任何给定点可以看到网格中的哪些点,即每次使用我的轨道控件更新相机位置时。
我的第一个想法是使用光线投射在相机和网格中的每个点之间创建一条光线。然后我可以找到哪些光线与模型相交,并从所有点的列表中删除与这些光线对应的点,从而留下相机可以看到的点列表。
到目前为止一切顺利,光线创建和相交代码被放置在渲染循环中(因为它必须在相机移动时更新),因此速度非常慢(很明显)。
gridPointsVisible = gridPoints.geometry.vertices.slice(0);
startPoint = camera.position.clone();
//create the rays from each point in the grid to the camera position
for ( var point in gridPoints.geometry.vertices) {
direction = gridPoints.geometry.vertices[point].clone();
vector.subVectors(direction, startPoint);
ray = new THREE.Raycaster(startPoint, vector.clone().normalize());
if(ray.intersectObject( defaultMesh ).length > 0){
gridPointsVisible.pop(gridPoints.geometry.vertices[point]);
}
}
在显示的示例模型中,创建了大约 2300 条光线,网格有 1500 个面,因此渲染需要很长时间。
所以我有 2 个问题:
- 是否有更好的方法来查找相机可以看到的对象?
- 如果没有,我可以加快 raycasting/intersection 检查速度吗?
提前致谢!
看看this example of GPU picking。
您可以做类似的事情,特别容易,因为您有一组有限且有序的球体。这个想法是您将使用着色器计算(可能基于位置)每个球体的平面颜色,并渲染到 off-screen 渲染目标。然后,您将解析颜色的渲染目标数据,并能够映射回您的球体。任何可见的颜色也是可见的球体。任何剩余的球体都被隐藏。这种方法应该比光线投射更快地产生结果。
WebGLRenderTarget
允许您在不绘制到 canvas 的情况下绘制到缓冲区。然后,您可以访问渲染目标的图像缓冲区 pixel-by-pixel(实际上是 RGBA 中的 color-by-color)。
对于映射,您将解析该缓冲区并创建您看到的所有独特颜色的列表(所有 non-sphere 对象都应该是其他平面颜色)。然后你可以遍历你的点——你应该知道每个球体应该是什么颜色,通过与使用的着色器相同的颜色计算。如果某个点的颜色在您找到的颜色列表中,则该点可见。
要优化这个想法,您可以降低渲染目标的分辨率。您可能会失去只有碎片可见的点数,但您可以调整分辨率以满足您的需要。此外,如果您的点少于 256 个,则只能使用红色值,这会将检查值的数量减少到每 4 个中有 1 个(仅检查 RGBA 像素的 R)。如果超过 256,包括检查绿色值等。
我的 Three.js 场景中有一个点网格(object3D 使用 THREE.Points),模型位于网格顶部,如下所示。在代码中,模型被称为 default mesh
并出于性能原因使用合并的几何体:
我正在尝试找出我的透视相机在任何给定点可以看到网格中的哪些点,即每次使用我的轨道控件更新相机位置时。
我的第一个想法是使用光线投射在相机和网格中的每个点之间创建一条光线。然后我可以找到哪些光线与模型相交,并从所有点的列表中删除与这些光线对应的点,从而留下相机可以看到的点列表。
到目前为止一切顺利,光线创建和相交代码被放置在渲染循环中(因为它必须在相机移动时更新),因此速度非常慢(很明显)。
gridPointsVisible = gridPoints.geometry.vertices.slice(0);
startPoint = camera.position.clone();
//create the rays from each point in the grid to the camera position
for ( var point in gridPoints.geometry.vertices) {
direction = gridPoints.geometry.vertices[point].clone();
vector.subVectors(direction, startPoint);
ray = new THREE.Raycaster(startPoint, vector.clone().normalize());
if(ray.intersectObject( defaultMesh ).length > 0){
gridPointsVisible.pop(gridPoints.geometry.vertices[point]);
}
}
在显示的示例模型中,创建了大约 2300 条光线,网格有 1500 个面,因此渲染需要很长时间。
所以我有 2 个问题:
- 是否有更好的方法来查找相机可以看到的对象?
- 如果没有,我可以加快 raycasting/intersection 检查速度吗?
提前致谢!
看看this example of GPU picking。
您可以做类似的事情,特别容易,因为您有一组有限且有序的球体。这个想法是您将使用着色器计算(可能基于位置)每个球体的平面颜色,并渲染到 off-screen 渲染目标。然后,您将解析颜色的渲染目标数据,并能够映射回您的球体。任何可见的颜色也是可见的球体。任何剩余的球体都被隐藏。这种方法应该比光线投射更快地产生结果。
WebGLRenderTarget
允许您在不绘制到 canvas 的情况下绘制到缓冲区。然后,您可以访问渲染目标的图像缓冲区 pixel-by-pixel(实际上是 RGBA 中的 color-by-color)。
对于映射,您将解析该缓冲区并创建您看到的所有独特颜色的列表(所有 non-sphere 对象都应该是其他平面颜色)。然后你可以遍历你的点——你应该知道每个球体应该是什么颜色,通过与使用的着色器相同的颜色计算。如果某个点的颜色在您找到的颜色列表中,则该点可见。
要优化这个想法,您可以降低渲染目标的分辨率。您可能会失去只有碎片可见的点数,但您可以调整分辨率以满足您的需要。此外,如果您的点少于 256 个,则只能使用红色值,这会将检查值的数量减少到每 4 个中有 1 个(仅检查 RGBA 像素的 R)。如果超过 256,包括检查绿色值等。