Is there an Object3D poperty to check if it's within camera frustum?

There is a Frustum.containsPoint or .intersectsBox() method that lets me manually check if a point or mesh is within the camera’s frustum. However, I need to do this once per frame on several objects, and the WebGLRenderer is already doing this at the same frequency. In order to avoid redundant calculations, is there a property of the Mesh I could check to see if it’s getting culled or not? I would love to avoid performing that check twice per frame, since I need to do it on several objects.

There’s this thread asking for a similar thing from 2018, and was wondering if a property that does this has been made available in the time since then?

No, users have to determine this manually if necessary.

One reason for this is that exposing the object’s frustum culling state can be perceived from certain users as buggy. The implemented view frustum culling test is actually conservative. So some objects pass the test although they are not in view. This is totally fine for a culling algorithm but probably not for more precise tests on app level.

If you still want to use the internal culling state, try it with this approach.

4 Likes

I was about to create a new topic about this…

The workaround you propose @Mugen87 requires you to traverse the entire scene. For a scene with a lot of objects, this will become an unnecessary bottleneck for something that is already done internally.

For my use-case I don’t really care if I hit false-positives if something is marked as visible while in fact it is not. The other way around would be worse… For example, I want to disable animation mixers for any mesh that isn’t currently visible on the screen, and re-enable them when they are. It isn’t a huge problem if some remain active for a while if a false-positive hits. The same would go for particle systems I suppose.

So instead of us having to reiterate over the scene again (while this is already being done internally), why is there an opposition about exposing isFrustumCulled on objects? If we simply document that the test is conservative and results might not be fully accurate, then users at least know what to expect.

EDIT:

I’ve tried this right before my call to .render():

        scene.traverse((v) => {
            if (!v.userData) {
                v.userData = {};
            }
            count++;
            v.userData.isVisible = false;
            v.onBeforeRender = (() => {
                v.userData.isVisible = true;
            });
        });

The problem here is that onBeforeRender is never called on Group or Object3D or anything that isn’t a renderable object (See Object3D.onBeforeRender not triggered for Object3D and Group objects. · Issue #14970 · mrdoob/three.js · GitHub).

So, without having to constantly recalculate a Box3 based on a world matrix of an object, what would
actually be the most efficient way to determine if an Object (renderable or not) is in the view frustum?

1 Like

I think Mugen said it could be considered “buggy” by some users because exposing its frustum status would give you the frustumCulled status of the previous frame, not the current one.

update() {
	// This would give you status of the previous frame
	object.isFrustumCulled;

	// FrustumCulled status gets updated
	renderer.render(scene, camera);

	// Now you'd get status of this frame
	// but your changes won't show up until next frame,
	// when the camera/object may have moved in/out of frustum again
	object.isFrustumCulled;
}

It could still be useful in some cases, but this buggy behavior would open the door to a lot of confusion.

1 Like

I don’t see why this is a problem. Sure, some users would get confused about this, but it’s the same as a matrix or matrixWorld that only gets updated after a render. How is this any different?

API-wise we could implement something like updateViewFrustum (or whatever a good name for this would be) that would effectively do the same as updateMatrix for example…

Then again, this would only be really useful if it would work on non-renderable containers like Object3D or Group. (Sidenote: Why does Group exist? It’s functionally exactly the same as an Object3D)

1 Like

“Group is almost identical to an Object3D. Its purpose is to make working with groups of objects syntactically clearer.”

1 Like

Yes and I’m actually not happy with this behavior. There have been considerations to change how world matrices are updated in three.js. One option is to return a matrix which always up-to-date whenever you request it. However, there are valid performance considerations about such a system. It would only work with a combination of caches/dirty flags and with a less flexible API (which means that would be a breaking change).

1 Like