Три 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});
  }

1 ответ

Я могу придумать два способа сделать это.

Во-первых, вы можете использовать raycaster (код из памяти, не совсем уверен, что он будет работать на 100% так):

  • Настройте raycaster лучом, направленным от камеры к вашему маркеру:

    // 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);
    
  • получить объекты, пересекающие этот луч

    // you might want to be a bit more specific
    const intersections = raycaster.intersectObjects(scene, true);
    
  • если первое пересечение не является маркером, оно хотя бы частично перекрыто

    if (intersections.length > 0 && intersections[0].object !== marker) {
      // hide marker...
    }
    

Это, вероятно, будет хорошо работать для меньшего числа объектов / объектов с ограниченным количеством граней. Для очень сложных объектов raycaster мучительно медленен, и вы можете прибегнуть к использованию предварительно визуализированной карты глубины.

  • перед рендерингом сцены визуализируйте только окклюдеры в карту глубины (вы можете использовать object.layers а также camera.layers ( Layer Docs), чтобы контролировать то, что визуализируется)

    // 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);
    
  • Теперь вы можете проецировать координаты маркера и сравнивать глубину из карты глубины в этой позиции с z-расстоянием маркера. Пожалуйста, посмотрите этот кодовый блок, чтобы узнать, как читать координаты мирового пространства с карты глубины.

Другие вопросы по тегам