Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/401.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Three.js检测对象被部分和完全遮挡的时间_Javascript_Three.js_3d_Occlusion_Occlusion Culling - Fatal编程技术网

Javascript 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

我试图检测Three.js中的一个对象何时被部分和完全遮挡,隐藏在另一个对象后面

我当前的简单解决方案将一条光线投射到对象的中心:

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例子:这还不能在所有浏览器上工作,不过感谢您花时间进行这两个演示!这真的很有用没问题!在某个时候写一篇博文:谢谢你花时间展示这两个演示!这真的很有用没问题!在某个时候写一篇博文: