三个js:我的点是可见的还是被遮挡的?

Din*_*ino 5 visibility occlusion-culling three.js

我在空间中有一个点在三个 js 查看器中表达一个向量。附加到这一点有一个“HTML 注释”

可见注释

当该点不可见时(在同一网格的其他表面后面或被其他网格隐藏),我想隐藏它。例如,在下图中,它应该被隐藏:

应该是不可见的

我正在使用一些代码来检查注释是否在另一个问题中建议的截锥体中,但这并不完全有效,因为只有当我非常大幅度地旋转对象时注释才会消失。见下图:

现在不可见

你能帮我解决我的问题吗?

到目前为止我的代码是:

const vector = new THREE.Vector3(x, y, z);

this.aCamera.updateMatrix();
this.aCamera.updateMatrixWorld(true);

let frustum = new THREE.Frustum();
frustum.setFromMatrix(new THREE.Matrix4().multiplyMatrices(this.aCamera.projectionMatrix, this.aCamera.matrixWorldInverse));

  // check if annotation is in view
  if (frustum.containsPoint(vector)) {
       anAnnotation.css({opacity: 0});
  } else {
        anAnnotation.css({opacity: 1});
  }
Run Code Online (Sandbox Code Playgroud)

Mar*_*fuß 4

我可以想到两种方法来做到这一点。

首先,您可以使用光线投射器(代码来自内存,不完全确定这将 100% 像这样工作):

  • 使用从相机指向标记的光线设置光线投射器:

    // somewhere outside
    const raycaster = new THREE.Raycaster();
    const v = new THREE.Vector3();
    
    // in the animation-loop
    v.copy(marker.position).sub(camera.position).normalize();
    raycaster.set(camera.position, v);
    
    Run Code Online (Sandbox Code Playgroud)
  • 获取与该射线相交的对象

    // you might want to be a bit more specific
    const intersections = raycaster.intersectObjects(scene, true);
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果第一个交叉点不是标记,则它至少部分被遮挡

    if (intersections.length > 0 && intersections[0].object !== marker) {
      // hide marker...
    }
    
    Run Code Online (Sandbox Code Playgroud)

对于数量较少的物体/面数有限的物体来说,这可能会很好地工作。对于非常复杂的对象,光线投射器非常慢,您可能需要使用预渲染的深度图。

  • 在渲染场景之前,仅将遮挡物渲染到深度图中(您可以使用object.layerscamera.layers图层文档)来控制渲染的内容)

    // outside animation-loop
    const depthMaterial =  new THREE.MeshDepthMaterial({
      depthPacking: THREE.RGBADepthPacking
    });
    
    const depthTarget = new THREE.WebGLRenderTarget(
      rendererWidth, 
      rendererHeight
    );
    
    
    // before rendering scene
    camera.layers.disable(MARKERS_LAYER);
    scene.overrideMaterial = depthMaterial;
    renderer.render(scene, camera, depthTarget);
    camera.layers.enable(MARKERS_LAYER);
    
    Run Code Online (Sandbox Code Playgroud)
  • 现在您可以投影标记的坐标,并将该位置的深度图的深度与标记的 z 距离进行比较。请参阅此代码笔,了解如何从深度图中读取世界空间坐标。