What is Three.js frustumCulled and when to disable it

In Three.js, performance optimization is key to maintaining smooth frame rates, and the frustumCulled property plays a vital role in this process. This article explains what frustumCulled is, how it works to improve rendering performance, and the specific scenarios where you must manually disable it to prevent objects from rendering incorrectly or disappearing from your 3D scene.

Understanding frustumCulled in Three.js

By default, Three.js enables frustum culling for all 3D objects (Object3D.frustumCulled = true).

The “frustum” is the three-dimensional region of space visible to the camera. It is shaped like a pyramid with the top cut off. Frustum culling is an optimization technique where Three.js checks if an object’s bounding box or bounding sphere is inside this visible region before rendering it.

To perform this check quickly, Three.js uses the object’s static geometry to calculate a bounding sphere. However, because this calculation happens on the CPU before the rendering step, it can sometimes become inaccurate.


When to manually disable frustumCulled

There are specific situations where the CPU-calculated bounding volume no longer matches the actual position or shape of the object. When this happens, Three.js may mistakenly believe an object is off-screen and stop rendering it, causing the object to flicker or suddenly disappear while still in the camera’s line of sight.

You can resolve this by setting the property to false:

mesh.frustumCulled = false;

Here are the primary scenarios where you should manually disable frustumCulled:

1. Vertex Shader Displacements (GPU Animations)

If you are using a custom ShaderMaterial to animate or displace vertices on the GPU (for example, creating waving water, wind-blown grass, or exploding particles), the CPU is unaware of these changes. The CPU still uses the original, flat geometry to calculate the bounding sphere. If the GPU pushes the vertices into the camera’s view while the original bounding sphere remains off-camera, Three.js will cull the object. Disabling frustum culling ensures the shader-displaced object remains visible.

2. Complex Skinned Meshes and Bone Animations

Skinned meshes (like 3D characters) are animated using a skeleton. Sometimes, character animations can cause hands, limbs, or held objects to stretch far beyond the character’s original bounding box. If the root of the character goes off-screen, Three.js might cull the entire mesh, causing the extended limbs or accessories to instantly disappear. Setting mesh.frustumCulled = false on the skinned mesh or its sub-meshes prevents this popping effect.

3. Dynamic Geometry Modifications

If you are constantly modifying the vertices of a geometry programmatically on the fly, the bounding sphere will become outdated. While you can manually recalculate the bounding sphere using geometry.computeBoundingSphere() after every change, doing so can be CPU-intensive. For frequently updated, highly dynamic geometries, disabling frustum culling is often a more performant and simpler solution.

4. Instanced Meshes with Wide Spreads

When using InstancedMesh to render thousands of identical objects (like trees or rocks) across a large map, Three.js calculates a single bounding box that encompasses all instances. If the camera looks away from the origin of the instanced mesh but is still looking at some of the instances spread across the map, the entire group might get culled. Disabling frustum culling on the InstancedMesh guarantees that all instances remain visible regardless of the camera’s position.