โšก 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 for loops 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