Guide
Game LOD (level of detail) explained
Level of detail (LOD) is how games stay playable when a scene contains thousands of objects the GPU cannot afford to draw at full fidelity. A hero mesh with 80,000 triangles looks great up close; at 200 meters it occupies a handful of pixels on screen, so rendering every buckle and pore wastes fill rate and vertex bandwidth. LOD systems automatically swap cheaper representations — fewer triangles, smaller textures, simplified materials, or flat impostors — as objects shrink in screen space. Done well, players never notice. Done poorly, you get the infamous pop-in where a detailed rock suddenly morphs into a low-poly lump. This guide explains mesh LOD chains, the metrics engines use to pick a level, texture mipmaps, impostors and hierarchical LOD, and how LOD fits into your frame budget alongside culling and batching.
Why LOD exists
Real-time rendering has hard limits. Each frame, the GPU must transform vertices, rasterize triangles, shade pixels, and write depth. Cost scales with triangle count, overdraw, texture resolution, and shader complexity. Open-world and multiplayer titles push draw calls into the thousands; mobile browsers running WebGL or WebGPU have even tighter ceilings.
LOD is a perceptual optimization: human vision resolves fine detail only where an object is large on screen. Distant geometry contributes little to the final image but can dominate GPU time if left unchecked. By maintaining multiple versions of the same asset at decreasing complexity, the engine spends triangles where they matter and saves them everywhere else.
LOD is not the same as culling
Frustum culling skips objects outside the camera view. Occlusion culling skips objects hidden behind walls. LOD still draws the object — just with a cheaper mesh or material. The techniques stack: cull what you cannot see, simplify what you can see but only barely.
Mesh LOD chains
The most common pattern is a LOD chain: LOD0 is the hero mesh (highest detail), LOD1 cuts triangle count roughly in half, LOD2 halves again, and so on until a final level or culled impostor. Artists or automated tools (Simplygon, Blender decimate, engine built-ins) generate these offline; runtime code picks which index to bind per instance.
Choosing switch distances
Naive implementations switch on world-space distance from the camera. That fails when field of view changes — a wide FOV makes distant objects larger on screen, so they need higher LOD sooner. Better engines use screen-space metrics:
- Screen coverage — projected bounding sphere radius in pixels; switch when coverage drops below a threshold.
- Screen size percentage — Unity’s
LODGroupuses the ratio of object height to screen height. - Error metrics — some pipelines store maximum geometric deviation per LOD and pick the coarsest level under a pixel error budget.
Tie LOD evaluation to the same camera used for rendering — including follow-camera smoothing and split-screen rigs — or switches will jitter when the view matrix lags the player position.
Crossfade vs hard switches
A hard switch swaps meshes instantly at a boundary — cheap but visible. Crossfade LOD (dithered opacity blend or vertex morph between two levels over a distance band) hides pops at the cost of briefly drawing both meshes. For hero characters near the camera, crossfade is worth it; for background props, hard switches are fine.
Texture LOD: mipmaps
Meshes are only half the story. A 4K albedo map on a distant wall still costs memory bandwidth when the GPU samples it, even if the mesh is low-poly. Mipmaps are precomputed half-resolution copies of a texture chain (512, 256, 128… down to 1×1). The GPU selects a mip level based on how densely the texture maps to screen pixels, reducing aliasing (shimmering moiré) and cache misses.
Mipmaps are the texture equivalent of mesh LOD and ship enabled by default in Unity, Unreal, and WebGL when you upload power-of-two textures. Non-power-of-two assets on some mobile GPUs cannot mip cleanly — pad or atlas them at build time. For web games, see our web image optimization guide for compression formats (ASTC, BC7, WebP) that pair with mip chains.
Texture streaming
Open worlds add texture streaming: only resident GPU memory holds mips needed for the current view; higher mips load asynchronously as you approach. Streaming interacts with mesh LOD — a LOD2 rock might bind a 256px texture while LOD0 uses 2K. Author material LOD groups so shader features (normal maps, parallax) drop on distant levels too, not just geometry.
Beyond mesh swaps
Impostors and billboards
At extreme distance, even a 200-triangle LOD mesh is wasteful. Impostors replace the mesh with a camera-facing quad textured from pre-rendered views (or a single baked snapshot). Trees, crowds, and city skylines often become impostor fields beyond a few hundred meters. The trade-off is parallax error when the player moves — rotate impostor atlases with view direction or blend between cardinal snapshots.
Hierarchical LOD (HLOD)
HLOD merges many static meshes in a region into one combined mesh (or impostor) at bake time. A city block of 500 draw calls becomes one at distance. Unreal’s World Partition and Unity’s HLOD volumes automate this for open worlds. Rebuild HLOD when level geometry changes; stale clusters are a common source of missing buildings in shipped patches.
LOD and collision
Rendering LOD must not drive physics meshes. Players walking into invisible walls because collision used LOD2 is a classic bug. Keep a separate simplified collision hull (convex decomposition or hand-authored low-poly) independent of visual LOD — the same principle as broad-phase vs narrow-phase in our collision detection guide.
Runtime integration
In data-oriented architectures, LOD selection often lives in a dedicated system that queries transform and camera components each frame — a natural fit for entity component systems. Batch LOD updates: computing screen size for 10,000 instances every frame is cheap vector math, but triggering GPU mesh uploads per object is not.
- Stagger updates — evaluate one quarter of instances per frame with hysteresis so LOD does not oscillate at boundaries.
- Hysteresis bands — switch to LOD1 at 15% screen size, but do not switch back to LOD0 until 18%, preventing flicker when the player strafes at the threshold.
- Forced LOD for cinematics — lock hero characters to LOD0 during close-ups regardless of engine auto-selection.
- Quality settings — expose a global LOD bias slider (PC: “Mesh Quality”; mobile: reduce max LOD0 distance) so low-end devices skip expensive levels entirely.
Profile with and without LOD. Tools like RenderDoc, Unity Frame Debugger, and browser performance panels show triangle counts per pass. If LOD1 still dominates, your chain is too aggressive at the top or materials are the real bottleneck.
Pop-in: causes and fixes
Pop-in is the visible moment an asset changes representation. Common causes and mitigations:
- Too few LOD levels — add intermediate steps; halving triangles each level is a rule of thumb, not a law.
- Aggressive switch distances — push LOD1 farther out or use screen-space metrics tied to FOV.
- Hard switches on silhouettes — trees and rocks need crossfade or impostor blends; interior props can hard-switch.
- Async streaming lag — show a low-res placeholder until high mips arrive; never flash pink missing-texture placeholders.
- Shadow LOD mismatch — shadow maps using a coarser mesh than the color pass create swimming shadows; align shadow cascade LOD policy.
- Grass and foliage cards — fade alpha on distant cards instead of deleting geometry abruptly.
Playtest LOD at target frame rates on minimum-spec hardware, not only on a dev workstation. Pop-in that is invisible at 120 FPS on a discrete GPU often screams on a phone thermal-throttling to 30 FPS with a narrower FOV.
2D and browser games
2D titles use LOD differently. Sprite sheets may ship multiple resolutions; the engine picks based on zoom level or device pixel ratio. Tile maps collapse layers at zoom-out. Particle systems reduce spawn counts and swap textures. Canvas games without GPU instancing benefit from off-screen culling and reducing animation frame rates for distant sprites — logical LOD even when no mesh chain exists.
Web games should respect the ~16.7 ms frame budget at 60 FPS. LOD plus object pooling beats raw triangle pushing on integrated graphics and mobile browsers where thermal throttling is common.
Production checklist
- Author LOD0–LOD2 (minimum) for every repeatable mesh; hero assets need LOD3+ or impostors.
- Generate LODs offline with consistent material IDs; verify normals and UVs do not break at low levels.
- Use screen-space switch metrics, not raw world distance alone.
- Enable mipmaps on all 3D textures; author texture LOD groups per material quality tier.
- Keep collision meshes independent of visual LOD.
- Add hysteresis to LOD switches; stagger per-instance evaluation across frames.
- Test pop-in on min-spec targets and wide/narrow FOV; crossfade silhouettes that matter.
- Expose a global LOD bias in graphics settings; profile triangle and draw-call counts per view.
LOD is invisible infrastructure until it fails. Investing in chains, metrics, and streaming early lets art teams ship dense worlds without rewriting the renderer when the first performance pass arrives two weeks before launch.
Related reading
- Game loop and frame timing explained — delta time, frame budgets, and where LOD evaluation fits
- Game camera systems explained — FOV, follow rigs, and screen-space LOD metrics
- Entity component system (ECS) in games explained — batching LOD selection across thousands of instances
- Collision detection in games explained — why physics hulls must stay separate from visual LOD