Skip to main content

Command Palette

Search for a command to run...

Game Foliage Rendering

Updated
3 min read
Game Foliage Rendering
T

Just a guy who loves to write code and watch anime.

The Core Problem

Real trees have tens of thousands of leaves. Rendering each leaf as a 3D mesh would mean hundreds of thousands of triangles per tree. Multiply by a forest and your GPU dies.


The Classic Solution: Alpha Cards

Flat quads (2 triangles) with a texture that has transparency baked in. The alpha channel defines what's see-through vs opaque.

A single alpha card might show 20 to 30 leaves in one texture. You get tons of visual density for almost no geometry.

What's typically 3D: trunk, main branches
What's alpha cards: leaf clusters scattered at branch endpoints

The catch: overdraw. When alpha cards overlap, the GPU has to blend them and figure out what's behind what. Layer too many and performance tanks.


Billboarding

Alpha cards that rotate to face the camera. The "billboard" part is the behavior, not the rendering technique.

This is useful for distant trees so they don't look paper-thin as you walk around them. Some games use cylindrical billboarding (it only rotates on the Y axis) for a more natural vertical look.


Culling: Don't Render What You Can't See

Frustum culling: only render what's inside the camera's view pyramid. Stuff behind you or off to the side? Skip it.

Occlusion culling: if a mountain is blocking a grass field, don't render that grass field.


LOD (Level of Detail)

Close objects get full detail. Far objects get simplified versions with fewer polygons.

Distant trees might become flat billboards. Distant grass fields might become a single texture. Your brain sees "green field" at that distance anyway.

This is why you sometimes see models "pop" when approaching them, because the LOD is switching.


Draw Calls

A draw call is you telling the GPU "render this thing now." The actual rendering is fast, but each call has CPU to GPU communication overhead.

10,000 individual grass blades means 10,000 draw calls, which causes a CPU bottleneck while the GPU sits idle waiting.


GPU Instancing

Tell the GPU once: "here's a mesh, here's 50,000 transforms, draw all of them." One draw call, 50,000 objects.

You provide two data types:

  • Per vertex (same for all instances): the mesh geometry

  • Per instance (different for each): position, rotation, scale, color

The vertex shader combines them. This works best when objects are identical or very similar, which is perfect for grass.


The Modern Approach: Geometry Over Transparency

Games like Ghost of Tsushima use GPU instancing with actual geometric grass blades instead of alpha cards.

More triangles? Yes, a lot more. A grass blade might be 6 to 20 triangles instead of just 2.

But faster? Often yes, because:

  • One draw call instead of thousands

  • No overdraw from transparency

  • No alpha sorting issues

  • Modern GPUs are extremely good at processing huge numbers of triangles

You're trading a problem GPUs struggle with (transparency and overdraw) for one they're excellent at (geometry).


How It All Stacks

  1. Culling removes stuff you can't see

  2. LOD simplifies stuff that's far away

  3. GPU instancing batches the remaining stuff into minimal draw calls

  4. Alpha cards or real geometry handles the actual rendering

Each layer helps. A million potential grass blades becomes manageable.


Bleeding Edge: Nanite (UE5)

Nanite virtualizes geometry so aggressively you can theoretically have millions of polygons on screen and the engine figures out what to actually render. Some developers are experimenting with actual geometric leaves using this. It's still early days.

Game Foliage Rendering