Javascript Three.js检测对象被部分和完全遮挡的时间
我试图检测Three.js中的一个对象何时被部分和完全遮挡,隐藏在另一个对象后面 我当前的简单解决方案将一条光线投射到对象的中心:Javascript Three.js检测对象被部分和完全遮挡的时间,javascript,three.js,3d,occlusion,occlusion-culling,Javascript,Three.js,3d,Occlusion,Occlusion Culling,我试图检测Three.js中的一个对象何时被部分和完全遮挡,隐藏在另一个对象后面 我当前的简单解决方案将一条光线投射到对象的中心: function getScreenPos(object) { var pos = object.position.clone(); camera.updateMatrixWorld(); pos.project(camera); return new THREE.Vector2(pos.x, pos.y); } function isOcclud
function getScreenPos(object) {
var pos = object.position.clone();
camera.updateMatrixWorld();
pos.project(camera);
return new THREE.Vector2(pos.x, pos.y);
}
function isOccluded(object) {
raycaster.setFromCamera(getScreenPos(object), camera);
var intersects = raycaster.intersectObjects(scene.children);
if (intersects[0] && intersects[0].object === object) {
return false;
} else {
return true;
}
}
但是,它不考虑对象的尺寸(宽度、高度和深度)
未被遮挡,因为对象的中心不在后面
由于对象的中心在后面而被遮挡
查看工作演示:
目前我认为我可以计算对象框的大小,并为框的每个角投射光线。但这可能还是有点太简单了:
var box = new THREE.Box3().setFromObject(object);
var size = box.getSize();
我想找到一种更稳健的方法,可以给出部分遮挡和完全遮挡的布尔值,甚至是遮挡百分比?搜索堆栈溢出和用于GPU拾取的三个.js示例。该概念可分为三个基本步骤: 将每个形状的材质更改为唯一的平面网格基本材质颜色。 使用唯一材质渲染场景。 读取渲染帧的像素以收集颜色信息。 您的场景允许您提出一些警告 只给你正在测试的形状一个独特的颜色,其他的都可以是黑色。 测试一个形状不需要渲染整个场景。您可以调整视口以仅渲染相关形状周围的区域。 因为您只为测试部分指定了一种颜色,所以其余的数据应该为零,这样可以更容易地找到与您的唯一颜色匹配的像素。 现在您有了像素数据,可以确定以下内容: 如果没有与唯一颜色匹配的像素,则形状被完全遮挡。 如果某些像素与唯一颜色匹配,则形状至少部分可见。 第二个项目符号表示形状至少部分可见。这是因为您无法使用当前拥有的信息测试完全可见性
我和其他人可能会有更好的解决方案,那就是第二次渲染相同的视口,但只让测试图形可见,这相当于零件完全可见。有了这些信息,将像素与第一次渲染进行比较。如果两者的数字相同,可能在唯一颜色像素的公差范围内,则可以说零件完全可见/未被遮挡。搜索堆栈溢出和用于GPU拾取的三个.js示例。该概念可分为三个基本步骤: 将每个形状的材质更改为唯一的平面网格基本材质颜色。 使用唯一材质渲染场景。 读取渲染帧的像素以收集颜色信息。 您的场景允许您提出一些警告 只给你正在测试的形状一个独特的颜色,其他的都可以是黑色。 测试一个形状不需要渲染整个场景。您可以调整视口以仅渲染相关形状周围的区域。 因为您只为测试部分指定了一种颜色,所以其余的数据应该为零,这样可以更容易地找到与您的唯一颜色匹配的像素。 现在您有了像素数据,可以确定以下内容: 如果没有与唯一颜色匹配的像素,则形状被完全遮挡。 如果某些像素与唯一颜色匹配,则形状至少部分可见。 第二个项目符号表示形状至少部分可见。这是因为您无法使用当前拥有的信息测试完全可见性
我和其他人可能会有更好的解决方案,那就是第二次渲染相同的视口,但只让测试图形可见,这相当于零件完全可见。有了这些信息,将像素与第一次渲染进行比较。如果两者的数字相同,可能在唯一颜色像素的公差范围内,则可以说零件完全可见/未被遮挡。我根据Jim01的答案成功获得了WebGL1的工作版本 首先创建第二个更简单的场景以用于计算:
pickingScene = new THREE.Scene();
pickingTextureOcclusion = new THREE.WebGLRenderTarget(window.innerWidth / 2, window.innerHeight / 2);
pickingMaterial = new THREE.MeshBasicMaterial({ vertexColors: THREE.VertexColors });
pickingScene.add(new THREE.Mesh(BufferGeometryUtils.mergeBufferGeometries([
createBuffer(geometry, mesh),
createBuffer(geometry2, mesh2)
]), pickingMaterial));
更快地将对象重新创建为缓冲区几何体以提高性能:
function createBuffer(geometry, mesh) {
var buffer = new THREE.SphereBufferGeometry(geometry.parameters.radius, geometry.parameters.widthSegments, geometry.parameters.heightSegments);
quaternion.setFromEuler(mesh.rotation);
matrix.compose(mesh.position, quaternion, mesh.scale);
buffer.applyMatrix4(matrix);
applyVertexColors(buffer, color.setHex(mesh.name));
return buffer;
}
根据网格名称添加颜色,例如id 1、2、3等
function applyVertexColors(geometry, color) {
var position = geometry.attributes.position;
var colors = [];
for (var i = 0; i < position.count; i ++) {
colors.push(color.r, color.g, color.b);
}
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
}
您可以在此处查看WebGL1工作演示:
使用这种方法需要注意的一点是,拾取场景需要与主场景中的更改保持同步。因此,如果对象移动位置/旋转等,也需要在拾取场景中更新它们。在我的示例中,摄影机正在移动,而不是对象,因此不需要更新
对于WebGL2,我们将有一个更好的解决方案:
但并非所有浏览器都支持此功能:
根据Jim01的答案,我成功地获得了WebGL1的工作版本 首先创建第二个更简单的场景以用于计算:
pickingScene = new THREE.Scene();
pickingTextureOcclusion = new THREE.WebGLRenderTarget(window.innerWidth / 2, window.innerHeight / 2);
pickingMaterial = new THREE.MeshBasicMaterial({ vertexColors: THREE.VertexColors });
pickingScene.add(new THREE.Mesh(BufferGeometryUtils.mergeBufferGeometries([
createBuffer(geometry, mesh),
createBuffer(geometry2, mesh2)
]), pickingMaterial));
更快地将对象重新创建为缓冲区几何体以提高性能:
function createBuffer(geometry, mesh) {
var buffer = new THREE.SphereBufferGeometry(geometry.parameters.radius, geometry.parameters.widthSegments, geometry.parameters.heightSegments);
quaternion.setFromEuler(mesh.rotation);
matrix.compose(mesh.position, quaternion, mesh.scale);
buffer.applyMatrix4(matrix);
applyVertexColors(buffer, color.setHex(mesh.name));
return buffer;
}
根据网格名称添加颜色,例如id 1、2、3等
function applyVertexColors(geometry, color) {
var position = geometry.attributes.position;
var colors = [];
for (var i = 0; i < position.count; i ++) {
colors.push(color.r, color.g, color.b);
}
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
}
您可以查看WebGL1工作
king demo在此:
使用这种方法需要注意的一点是,拾取场景需要与主场景中的更改保持同步。因此,如果对象移动位置/旋转等,也需要在拾取场景中更新它们。在我的示例中,摄影机正在移动,而不是对象,因此不需要更新
对于WebGL2,我们将有一个更好的解决方案:
但并非所有浏览器都支持此功能:
太棒了,我不知道“GPU拾取”的方法。看起来这里有一个例子做了一些工作:并发现了这个WebGL2例子:这还不能在所有浏览器上工作,虽然很棒,但不知道“GPU拾取”的方法。看起来这里有一个例子做了一些工作:并发现了这个WebGL2例子:这还不能在所有浏览器上工作,不过感谢您花时间进行这两个演示!这真的很有用没问题!在某个时候写一篇博文:谢谢你花时间展示这两个演示!这真的很有用没问题!在某个时候写一篇博文: