Frustum & View Frustum Culling - Sixth 3D
Table of Contents
1. Frustum & View Frustum Culling
The view frustum is a truncated pyramid-shaped volume that represents everything the camera can see. Objects completely outside this volume are skipped during rendering — a powerful optimization called frustum culling.
1.1. The Six Frustum Planes
The frustum is defined by six clipping planes:
| Plane | Purpose |
|---|---|
| Left | Left edge of viewport |
| Right | Right edge of viewport |
| Top | Top edge of viewport (smaller Y in Y-down) |
| Bottom | Bottom edge of viewport (larger Y) |
| Near | Closest visible distance from camera |
| Far | Farthest visible distance from camera |
Each plane divides 3D space into "inside" (visible) and "outside" (culled). An object must pass all six plane tests to be considered potentially visible.
1.2. Frustum Culling vs Backface Culling
These are complementary optimizations at different levels:
| Optimization | Level | What it skips |
|---|---|---|
| Frustum culling | Object level | Entire composite shapes + children |
| Backface culling | Polygon level | Individual triangles facing away |
Frustum culling happens first during the transform phase — entire object trees are skipped with a single bounding box test. Backface culling happens later during rasterization — individual triangles are checked before being drawn.
For best performance, use both: organize your scene with composite shapes for effective frustum culling, and enable backface culling on closed meshes.
2. How Frustum Culling Works in Sixth 3D
Frustum culling is applied automatically to all composite shapes during Phase 2 of the rendering loop:
- Update frustum: Compute 6 planes from camera FOV and viewport size
- For each composite shape:
- Get its Axis-Aligned Bounding Box (AABB)
- Transform all 8 corners to view space
- Test against frustum using intersectsAABB()
- If outside: skip the entire composite and all children
- If inside: continue transforming children
2.1. The AABB Intersection Algorithm
The intersection test uses an optimized "P-vertex" approach:
For each plane, instead of testing all 8 corners of the bounding box, we test only the P-vertex — the corner most aligned with the plane normal. If this "best" corner is behind the plane, the entire box must be outside the frustum.
- Plane normal points into the frustum (toward visible region)
- P-vertex: select corner based on normal direction
- If normal.x > 0 → use maxX (rightmost corner)
- If normal.x < 0 → use minX (leftmost corner)
- Same logic for Y and Z
- Test:
dot(normal, P-vertex) < distance→ outside
This reduces from 48 tests (8 corners × 6 planes) to just 6 tests per object.
3. Performance Benefits
Frustum culling can dramatically improve performance for large scenes:
- High cull % (60-90%): Excellent — most objects skipped entirely
- Medium cull % (20-60%): Moderate benefit
- Low cull % (0-20%): Limited benefit — most objects visible
A composite shape that is culled skips:
- Transforming all its children
- Computing bounding boxes for children
- All polygon-level operations (backface culling, rasterization)
Open Developer Tools (F12) to see real-time frustum culling statistics.
4. Scene Design for Effective Culling
Frustum culling works best when you organize your scene into well-defined composite shapes:
// Good: Each building is a separate composite AbstractCompositeShape cityBlock = new AbstractCompositeShape(); for (Building building : buildings) { AbstractCompositeShape buildingComposite = new AbstractCompositeShape(); buildingComposite.add(buildingWalls); buildingComposite.add(buildingRoof); buildingComposite.add(buildingInterior); cityBlock.add(buildingComposite); } // Less effective: Everything in one giant composite AbstractCompositeShape allObjects = new AbstractCompositeShape(); allObjects.add(building1Walls); allObjects.add(building1Roof); allObjects.add(building2Walls); // ... hundreds of shapes directly in root
Best practices:
- Use composites to group objects that occupy a bounded region of space
- Keep bounding boxes tight (don't add distant objects to the same composite)
- Nest composites hierarchically for multi-level culling (city → block → building)
- Call updateBoundingBox() after moving shapes
5. Technical Details
The Frustum class:
- Computes planes in view space (camera at origin, looking along +Z)
- FOV derived from
projectionScale = width / 3(≈112° horizontal FOV) - Default clip distances: Near = 1.0, Far = 10000.0
- Planes stored in Hesse normal form: (normal vector, distance)
The frustum is updated once per frame in ShapeCollection.transformAllShapes() before processing composite shapes.