THREE.js check if object is in frustum
Asked Answered
N

4

6

I have been tinkering around with Three.js and I have a canvas I'd like to use as kind of a GUI. For that I have to check if an object is in the camera frustum.

My current code:

camera.updateMatrix();
camera.updateMatrixWorld();

const frustum = new THREE.Frustum();
const projScreenMatrix = new THREE.Matrix4();
projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );

frustum.setFromProjectionMatrix( camera.projectionMatrix );

if(frustum.containsPoint( mesh.position )){
    // stuff happens...
};

frustum.containsPoint() keeps returning false. What am I doing wrong here?

Nonmetallic answered 22/7, 2014 at 2:21 Comment(3)
A Frustum takes 6 Planes as arguments, you're not providing anything. That's probably why it doesn't work.Uropygium
So how would i go about cloning the camera frustum?Nonmetallic
An example of that is in this answer: #10859099Uropygium
U
9

Your code is using

frustum.setFromMatrix( camera.projectionMatrix );

But that isn't the matrix you want. Instead use:

frustum.setFromMatrix( new THREE.Matrix4().multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ) );

as answered in How to determine if plane is in Three.js camera Frustum

Uropygium answered 22/7, 2014 at 9:16 Comment(0)
A
0

Three.js is doing view frustum Culling internally and only rendering when in camera frustum. Assuming that your Boundig Volumes are calculated correct, you can track weather a renderable Object3D is inside the camera view frustum when Object3D.onBeforeRender callback is called in your current frame

Alvinia answered 23/3, 2021 at 17:3 Comment(0)
I
0

Here is what I did to find if a mesh is in camera view (within 100ms):

mesh.onBeforeRender = function() {
    if (mesh.userData.inViewID) clearTimeout(mesh.userData.inViewID);
    mesh.userData.inViewID = setTimeout(()=>{
        mesh.userData.inView = false;
        console.log("out of view");
    }, 100);
    if (!mesh.userData.inView) { 
        mesh.userData.inView = true;
        console.log("in view");
    }
}
Idou answered 1/9, 2023 at 0:32 Comment(0)
B
0

now in version r166 the code has changed slightly so I add an update.

const frustum = new THREE.Frustum();

camera.updateMatrix();
camera.updateMatrixWorld();
mesh.updateMatrix();
mesh.updateMatrixWorld();

frustum.setFromProjectionMatrix(
new THREE.Matrix4().multiplyMatrices(
        camera.projectionMatrix,
        camera.matrixWorldInverse
    )
);

const intesectedMesh = frustum.intersectsObject(mesh);

if(intesectedMesh){
//Do something
}

Regards

Bagby answered 29/7 at 10:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.