Hiding two big models if the camera is no longer looking at them/ in view?

Hi all! so I have 2 massive models they are “land/terrain” or whatever you want to call them anyways i am trying to hide them if the camera is no longer looking at them so basically they are out of view and show them when they are in view…

but it doesn’t really work as expected and seems to depend on what way the camera is facing rather than if they are actually in view or not…

here’s the code i’ve been trying with any ideas?

const frustum = new THREE.Frustum()
const matrix = new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse)
frustum.setFromProjectionMatrix(matrix)

if (!frustum.containsPoint(landmass.position)) {
    console.log('Out of view');
    landmass.visible = false;
} else {
    console.log('in of view');
    landmass.visible = true;
}

if (!frustum.containsPoint(landmass2.position)) {
    console.log('Out of view 2');
    landmass2.visible = false;
} else {
    console.log('in of view 2');
    landmass2.visible = true;
}

any ideas of how to make this “work better”?

im guessing .containsPoint isn’t the right approach ? as the models are big…

What you’re thinking of is called “frustum culling”.
Maybe you’re expecting performance gains by making “massive” models invisible if not in view. I believe, this type of optimisation is already built-in into Three.js. See this.

1 Like

like @vielzutun.ch said, this is already done for you by threejs, it won’t render objects that can’t be seen. if this has any other reason why you’d want to know if an object is hidden or not there’s a very fast trick without any math: obj.onBeforeRender is not called when the renderer culls it, hence you can do something like this:

let check = false
...
obj.onBeforeRender = () => (check = true)
...
function loop() {
  check = false
  gl.render(scene, camera)
  console.log(`obj is ${check ? "" : "in"}visible!`) 

i use it to make objects jump up when they pop into view: UseIntersect and scrollcontrols - CodeSandbox (scroll down)

and if this is about performance, the thing you want to try is called THREE.LOD. this would be about making things that are visible but are far away less detailed.

2 Likes

Yes it is but lets say i have a “character” in 3d person view and there’s a huge model behind them rendering they can’t see because the model is still in distance i want to hide it completely if it serves no purpose visually as its not in view … i thought frustum culling only took effect after you went past the “far” threshold ?

Frustum culling is mainly about culling objects which are completely left, right, above or below the frustum sides. If you want to cull objects which are within frustum bounds but are too far away to have any visual impact, then LOD is the way to go, as suggested by @drcmda .

On a related note: the rendering is done from the perspective of a camera. If you use a camera which shows a “3rd person” view, that will probably be entirely different from what the person itself sees. And I don’t see how a “3rd person viewer” could judge (algorithmically), what might be visible for the actual 1st person.

to know something is completely behind something else is probably doable with raycasting though that will be expensive again. i have little experience with three-mesh-bvh but i think it is mostly for static scenes (?). something that’s really simple to implement and can give you a decent boost is lod: Re-using geometry and level of detail - CodeSandbox if you scroll out you see them cycle through detail grades.