Home

Awesome

UnityGrassRenderingIndirectExample

This is a hobby project I created to learn how to use compute shaders and GPU APIs like Graphics.DrawMeshInstancedIndirect to efficiently render large amounts of grass on a terrain.

https://github.com/EricHu33/UnityGrassIndirectRenderingExample/assets/13420668/a5110d44-2f3a-474e-a7a6-467755b2f99b

How To Use

  1. add Hi-Z Buffer Controller component to your main camera

  2. add Indirect Draw Controller componnent to your terrain game object, other required component will automatically add.

image

  1. on the terrain inspector, choose magic grass detail painter, this painter can paint the terrain detail into select channel.

image

  1. in the Indirect Draw Controller Component inspector, Add Magic Grass Render Model scriptable object into the model list, each model is pair with 1 detail map's channel, For example, the first model will pair with R channel of detail map, the second model will pair with G channel of the detail map.

image

  1. you can create Magic Grass Render Model scriptable object by right click on the project window and select Create/MagicGrass/MagicGrassRenderModel

image

Right now, the tool and script provided in the project has below features :

To make Object interact with grasses.

Store Img (25)

Here are the grass shader's features:

This is not a production-ready project:

About the overall implementation :

The overall logic structure is similar as this video

モバイル向け大量描画テクニック

APIs I use

For generating a massive amount of foliage on terrain in Unity, Graphics.DrawMeshInstancedIndirect(and RenderMeshIndirect) offers the fastest approach. While regular GPU instancing in Unity limitseach batch to 1023 objects (or fewer depending on the device), InstancedIndirect bypasses this restriction, allowing us to draw significantly more meshes with a single call.

Logic

The key logic is describe as follow image.

Untitled

  1. Split the terrain into 16 cells
  2. Cull-Unvisible Cells: This is a crucial optimization step. Before performing GPU-based Hi-Z culling, we perform a preliminary cull on the CPU. This involves identifying and discarding cells that are not visible to the camera. Since feeding all grass data into a compute buffer, even for invisible cells, would consume a significant amount of VRAM. By efficiently culling cells on the CPU, we drastically reduce VRAM usage.
  3. Per-Cell Grass Sampling: For each visible cell:
    • Utilize a compute shader to sample the terrain's detail map. The detail map defines the position and type of grass on the terrain.
    • Parameters within the compute shader allow us to further fine-tune the rotation and density of the grass within the cell.
    • The sampled grass data for the cell is then transferred into a compute buffer.
  4. Hi-Z Culling:
    • The compute buffer containing the grass data for all visible cells is passed to a specialized Hi-Z culling compute shader.
    • This shader efficiently discards grass instances that are occluded by other geometry in the scene, along side frustum culling, further reducing the number of instances to be drawn.
    • An append buffer is used to collect the visible grass instances.
  5. Draw the grass instances with DrawMeshInstancedIndirect.

Some side note :

Summary :

Based on the commit history, I wrote the project around 1 and half year ago. At that time I learned many things when working on this small project. Such as how Unity terrain and how splat map works(and why unity’s terrain is kinda slow).

I also found that I blew up my vram before I implement the cpu-side culling and split the world with cells. Rightnow it use CullingGroup API since it’s dead-simple to implement, but a quadtree or use burst compiler with frustum culling on cpu side is also worth trying in the future.

I put a lot of time implement all the shading logic/paramter of the grass shader (And the code is pretty dirty now….). Ghost of Tsushima GDC talk is my main inspiration.

References :

モバイル向け大量描画テクニック

Procedural Grass in 'Ghost of Tsushima'

NiloCat's instanced indirect example(this is a much simpler project for beginner)

How to make HDRP shadergraph shader become InstanceIndirect compatible

How to make shadergraph shader become InstanceIndirect compatible - Cyanilux's Twtitter Posts

Licenses Notice:

The assets under folder [TerrainSampleAssets] is from Unity's Terrain Sample project, which is govern by Unity's UCL