Tutorial Unity

GPU-Accelerated Grass in Unity

Build a field of natural-looking grass from a small billboard mesh, distribute it with an OctoShaper graph, and switch from prefab previews to efficient indirect GPU drawing. By the end, you will have a reusable graph with exposed controls for field size, spacing, density, and height variation.

Graph recipe

What you will make

The graph scatters billboard clusters, varies their transforms with random values and noise, then renders the finished field with indirect GPU instancing.

Distribute Grid + disc samples
Cluster Repeat billboards
Vary Rotation + scale
Shape Height noise
Render Indirect drawing

You need an OctoShaper graph, a grass billboard prefab for previewing, and a quad mesh with an instancing-compatible material. See Installation or Node Graph Basics if needed.

Video companion

See the graph assembled in Unity

The written instructions below are complete on their own. Timestamp links are included only where seeing an edit or result in motion is useful.

1. Establish the grass clusters

  1. Add Distribute Points In Grid after the graph input.
  2. Expose grid size and spacing as parameters.
  3. Connect Sample Points In Disc Per Element and raise its sample count until each grid point becomes a loose clump.

Video reference: distributing and sampling points at 0:26

2. Build each billboard cluster

  1. Connect Expand Per Element and set its repeat count to 2.
  2. Add Set Random Rotation Attribute and randomize the Y axis from −180° to 180°.
  3. Add Spawn Prefab and assign the billboard prefab for previewing. Translate it upward if its roots sit below the ground.

Video reference: layering and previewing billboards at 1:20

3. Add controlled variation

  1. Add Jitter Scale, enable uniform scaling, and use a range of roughly 0.5 to 1.0.
  2. Add Jitter Rotation with a restrained tilt of about −20° to 20°.
  3. Check the field from above and from ground level, then adjust sample count and translation as needed.

Video reference: adding scale and rotation variation at 3:24

4. Create coherent height variation

  1. Add low-frequency Perlin Noise 2D and sample it from each element's position.
  2. Add 1 to move the noise out of its negative range, then feed the value into all components of a Vector3 attribute such as Max Scale.
  3. Bind Max Scale to Jitter Scale's maximum input. Multiply the noise first—around 2 is a useful starting point—when you want stronger contrast.
  4. Expose frequency, strength, grid spacing, and field size as parameters.

Video reference: driving scale with positional noise at 4:34

5. Switch to indirect GPU drawing

Once the distribution looks right, replace the prefab preview with the production rendering path.

  1. Disconnect or remove Spawn Prefab from the completed graph.
  2. Add Draw Instanced Indirect.
  3. Assign the grass quad and an instancing-compatible material.
  4. Run the graph with a ProceduralGraphExecutor. The grass should render without creating individual GameObjects.

You can still change the exposed graph parameters and regenerate the field. See Runtime Generation for the executor workflow.

Video reference: replacing prefabs with indirect drawing at 11:59

Tuning checklist

  • Visible grid: increase disc radius or sample count before shrinking grid spacing.
  • Flat from above: add a small rotation jitter, then check the result from both top and side views.
  • Variation feels noisy: lower the Perlin frequency so nearby grass shares a similar height.
  • Too many scene objects: confirm that the graph ends with Draw Instanced Indirect rather than Spawn Prefab.

Where to go next

Once the field is working, expose density, spacing, noise frequency, and noise strength as parameters. You can then connect those controls to gameplay using Runtime Parameters, or explore the exact inputs and attribute effects of each building block in the Node Catalog.