javascriptthree.js3docclusionocclusion-culling

Three.js detect when object is partially and fully occluded


I'm trying to detect when an object in Three.js is partially and fully occluded (hidden behind) another object.

My current simple solution casts a single ray to the the center of the object:

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;
  }
}

However it doesn't account for the object's dimensions (width, height, depth).

Not occluded (because center of object is not behind) Object not occluded

Occluded (because center of object is behind) Object occluded

View working demo:

https://jsfiddle.net/kmturley/nb9f5gho/57/

Currently thinking I could calculate the object box size, and cast Rays for each corner of the box. But this might still be a little too simple:

var box = new THREE.Box3().setFromObject(object);
var size = box.getSize();

I would like to find a more robust approach which could give partially occluded and fully occluded booleans values or maybe even percentage occluded?


Solution

  • Search Stack Overflow and the Three.js examples for "GPU picking." The concept can be broken down into three basic steps:

    1. Change the material of each shape to a unique flat (MeshBasicMaterial) color.
    2. Render the scene with the unique materials.
    3. Read the pixels of the rendered frame to collect color information.

    Your scenario allows you a few caveats.

    1. Give only the shape you're testing a unique color--everything else can be black.
    2. You don't need to render the full scene to test one shape. You could adjust your viewport to render only the area surrounding the shape in question.
    3. Because you only gave a color only to your test part, the rest of the data should be zeroes, making finding pixels matching your unique color much easier.

    Now that you have the pixel data, you can determine the following:

    The second bullet says that the shape is "at least partially" visible. This is because you can't test for full visibility with the information you currently have.

    What I would do (and someone else might have a better solution) is render the same viewport a second time, but only have the test shape visible, which is the equivalent of the part being fully visible. With this information in hand, compare the pixels against the first render. If both have the same number (perhaps within a tolerance) of pixels of the unique color, then you can say the part is fully visible/not occluded.