Optimizing Raycasting Performance in glTF Models
Interactive 3D applications often experience frame rate drops when executing raycasting against complex glTF models due to high polygon counts and deep scene graphs. This guide outlines the most effective strategies to optimize raycasting performance, detailing techniques such as spatial partitioning, proxy geometry, selective testing, and execution throttling to ensure smooth user interactions.
Use Simplified Proxy Geometries (Hitboxes)
Standard glTF models often contain thousands or millions of triangles. Instead of casting rays against detailed render meshes, associate interactive objects with simplified, invisible collision proxies. Primitive shapes such as boxes, spheres, or low-poly convex hulls serve as hitboxes. Raycasting against a 12-triangle box instead of a 50,000-triangle character mesh drastically reduces mathematical intersection calculations to negligible levels.
Implement Bounding Volume Hierarchies (BVH)
When picking must occur against exact surface geometry—such as
precise sculpting, painting, or complex CAD inspection—implement an
accelerated Bounding Volume Hierarchy (BVH). Without BVH, a raycaster
tests every single triangle sequentially (\(O(N)\) complexity). A BVH organizes
triangles into a tree of nested bounding boxes, allowing the raycaster
to eliminate vast numbers of triangles at each tree node (\(O(\log N)\) complexity). In WebGL
ecosystems like Three.js, libraries such as three-mesh-bvh
yield massive speedups for complex glTF meshes.
Filter Targets Before Raycasting
Never pass the entire glTF root scene or scene graph directly to the raycaster. glTF hierarchies frequently contain structural groups, bones, cameras, and non-interactive environmental elements. Maintain a separate, flat array containing only the objects designated as interactive. Alternatively, use layer masks to ensure the raycaster only evaluates relevant objects, preventing unnecessary traversal down empty branches of the model graph.
Rely on Broad-Phase Checks First
Ensure your raycasting routine executes a broad-phase test before evaluating individual triangles. A broad-phase check tests intersection against the object's axis-aligned bounding box (AABB) or bounding sphere. If the ray does not intersect the coarse bounding volume, the engine immediately skips all triangle tests for that mesh. Most modern 3D engines do this by default, but deep glTF hierarchies can cause redundant checks if bounding volumes are not cached or updated properly.
Throttle and Decouple Raycasting from the Render Loop
Raycasting on every frame or on every raw pointermove
event consumes excessive CPU cycles. Optimize invocation by:
- Throttling: Limiting raycast execution to a fixed
interval (e.g., once every 16ms to 50ms) using a timer or
requestAnimationFrame. - Event-Driven Invocation: Only triggering raycasts
on discrete user actions such as
pointerdownorclick, rather than continuously tracking hover states. - Movement Thresholds: Skipping calculations if the pointer has moved fewer than a set number of pixels since the last evaluation.
Consider GPU-Based Color Picking
For scenes featuring thousands of separate interactive glTF instances or dense particle meshes, CPU-based raycasting becomes a bottleneck regardless of spatial optimization. In such scenarios, GPU-based picking provides superior scalability. In this approach, each pickable object is rendered off-screen into a low-resolution framebuffer using a unique solid color as an ID. Sampling the single pixel under the cursor reveals the exact object clicked instantly, completely bypassing CPU geometric intersection tests.