โก Performance
Asset Optimization
3D assets are often the biggest performance bottleneck. The glTF format (.gltf / .glb) is the standard for web 3D and supports Draco compression for geometry and KTX2 for textures, both of which drastically reduce file sizes and GPU memory usage. Tools like gltfpack and meshoptimizer can further optimize meshes by simplifying geometry and improving GPU cache efficiency.
Reuse geometries and materials across meshes whenever possible โ creating new ones for each object wastes memory and prevents batching.
Draw Calls
Every time the GPU draws a group of triangles with a given material, thatโs a draw call. Each one has CPU overhead, so reducing the total count is one of the most impactful optimizations. Techniques include:
- Batching โ combining multiple meshes that share a material into a single draw
- Instancing โ drawing many copies of the same geometry in one call, each with different transforms
- Merging โ baking multiple static meshes into one geometry at build time
Level of Detail (LOD)
LOD swaps high-poly models for simpler versions as objects get farther from the camera. At a distance, a character might go from 10,000 triangles to 500 โ the player wonโt notice, but the GPU will.
Culling
Donโt render what isnโt visible. Frustum culling (built into most engines) skips objects outside the cameraโs view. Occlusion culling skips objects hidden behind other objects. Distance culling removes objects beyond a threshold โ often paired with fog to hide the cutoff.
Shadows
Shadows are expensive. Bake static shadows into lightmaps where possible. For dynamic shadows, limit the shadow-casting distance and the number of lights that cast shadows. Simpler shadow techniques (blob shadows, projected textures) can look good enough at a fraction of the cost.
Materials
Simpler materials are cheaper. An unlit material is faster than a physically-based one. If an object doesnโt need lighting, donโt compute it. Choose the simplest material that achieves the look you need.
Spatial Partitioning
For collision detection or querying nearby objects, iterating over every entity is wasteful. Spatial hashing, octrees, and BVH (Bounding Volume Hierarchies) partition space so you only check objects that are close together.
Profiling
Donโt optimize blindly. Use your browserโs performance profiler (Chrome DevTools Performance tab, Firefox Profiler) to find actual bottlenecks. Measure GPU time vs. CPU time โ they have different solutions.
JavaScript Patterns
In hot loops (code running every frame for many entities), micro-optimizations matter:
- Prefer
forloops over.forEach/.mapโ they avoid function call overhead and allocations - Mutate objects in place (
Object.assign, set properties directly) rather than creating new ones with spread ({ ...obj }) - Avoid allocating new objects, arrays, or vectors per frame โ reuse them
Resources
- gltf-pipeline
- gltf-transform
- glTF-Compressor by Khronos
- Blender mesh-gpu-instancing (demo)
- Three.js LOD (Drei Detailed)
- PerspectiveCamera.far + Fog
- Spatial hashing (Yuka, other video)
- Drei Performance Monitor
- Fixed update
- How Games Use โCullingโ to Be More Efficient by SimonDev
- Three.js Optimization - Best Practices and Techniques
- PlayCanvasโs guidelines
- Tojiroโs WebXR Scene Optimization article
- Optimizing scenes for better WebGL performance by Verge3D
- Meta WebXR optimizations talk
- Bullet Hell article (Unity)