Skip to content

Instantly share code, notes, and snippets.

@Cyanilux
Last active July 30, 2025 14:54
Show Gist options
  • Save Cyanilux/e7afdc5c65094bfd0827467f8e4c3c54 to your computer and use it in GitHub Desktop.
Save Cyanilux/e7afdc5c65094bfd0827467f8e4c3c54 to your computer and use it in GitHub Desktop.

Revisions

  1. Cyanilux revised this gist Jun 2, 2021. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions DrawGrass.cs
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    // https://twitter.com/Cyanilux/status/1396848736022802435

    // Requires a specific shader to read the _PerInstanceData buffer at SV_InstanceID
    // I use a shader made in Shader Graph, See : https://gist.github.com/Cyanilux/4046e7bf3725b8f64761bf6cf54a16eb
    // Also note, there's no frustum culling involved in this example. Typically a compute shader is used for this.
  2. Cyanilux revised this gist May 26, 2021. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion DrawGrass.cs
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,6 @@
    // Note requires a specific shader to read the _PerInstanceData buffer at SV_InstanceID
    // Requires a specific shader to read the _PerInstanceData buffer at SV_InstanceID
    // I use a shader made in Shader Graph, See : https://gist.github.com/Cyanilux/4046e7bf3725b8f64761bf6cf54a16eb
    // Also note, there's no frustum culling involved in this example. Typically a compute shader is used for this.

    using UnityEngine;

  3. Cyanilux revised this gist May 24, 2021. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions DrawGrass.cs
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,6 @@
    // Note requires a specific shader to read the _PerInstanceData buffer at SV_InstanceID
    // I use a shader made in Shader Graph, See : https://gist.github.com/Cyanilux/4046e7bf3725b8f64761bf6cf54a16eb

    using UnityEngine;

    public class DrawGrass : MonoBehaviour {
  4. Cyanilux created this gist May 24, 2021.
    104 changes: 104 additions & 0 deletions DrawGrass.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,104 @@
    using UnityEngine;

    public class DrawGrass : MonoBehaviour {

    public int count; // If DrawMeshInstanced is used, this is limited to a max of 1023. No limit for DrawMeshInstancedIndirect
    public float range; // (terrain width)

    public Terrain terrain;

    public Mesh mesh;
    public Material material;

    private Matrix4x4[] matrices;
    private MaterialPropertyBlock MPB;
    private UnityEngine.Rendering.ShadowCastingMode shadowCasting = UnityEngine.Rendering.ShadowCastingMode.Off;
    private bool receiveShadows = true;

    private Bounds bounds;
    private ComputeBuffer instancesBuffer;
    private ComputeBuffer argsBuffer;

    private struct InstanceData {
    public Matrix4x4 matrix;

    public static int Size() {
    return sizeof(float) * 4 * 4;
    }
    }

    public void OnEnable() {
    MPB = new MaterialPropertyBlock();

    /*
    If using DrawMeshInstanced,
    matrices = new Matrix4x4[count];
    float range = 5f;
    for (int i = 0; i < count; i++) {
    float height = Random.Range(0.5f, 1.2f);
    Vector3 position = new Vector3(Random.Range(-range, range), height * 0.5f, Random.Range(-range, range));
    Quaternion rotation = Quaternion.Euler(0, Random.Range(0f, 360f), 0);
    Vector3 scale = new Vector3(1, height, 1);
    matrices[i] = Matrix4x4.TRS(position, rotation, scale);
    }
    */

    // If using DrawMeshInstancedIndirect,
    bounds = new Bounds(transform.position, new Vector3(101, 1, 101));
    InitializeBuffers();
    }

    private void InitializeBuffers() {
    // Args
    uint[] args = new uint[5] { 0, 0, 0, 0, 0 };
    args[0] = (uint)mesh.GetIndexCount(0);
    args[1] = (uint)count;
    args[2] = (uint)mesh.GetIndexStart(0);
    args[3] = (uint)mesh.GetBaseVertex(0);
    argsBuffer = new ComputeBuffer(1, args.Length * sizeof(uint), ComputeBufferType.IndirectArguments);
    argsBuffer.SetData(args);

    // Instances
    InstanceData[] instances = new InstanceData[count];
    for (int i = 0; i < count; i++) {
    InstanceData data = new InstanceData();

    //Vector3 position = new Vector3(Random.Range(-range, range), 0, Random.Range(-range, range));
    Vector3 position = new Vector3(Random.Range(0, range), 0, Random.Range(0, range));

    float height = Random.Range(0.3f, 0.9f);
    float y = terrain.SampleHeight(position);

    //position.y = (height - 1) * 0.5f;
    position.y = y + (height) * 0.5f;
    Quaternion rotation = Quaternion.Euler(0, Random.Range(0f, 360f), 0);
    Vector3 scale = new Vector3(1, height, 1);

    data.matrix = Matrix4x4.TRS(position, rotation, scale);
    instances[i] = data;
    }

    instancesBuffer = new ComputeBuffer(count, InstanceData.Size());
    instancesBuffer.SetData(instances);
    material.SetBuffer("_PerInstanceData", instancesBuffer);
    }

    public void Update() {
    //Graphics.DrawMeshInstanced(mesh, 0, material, matrices, count, MPB, shadowCasting, receiveShadows);

    //bounds = new Bounds(transform.position, new Vector3(101, 1, 101));
    Graphics.DrawMeshInstancedIndirect(mesh, 0, material, bounds, argsBuffer, 0, MPB, shadowCasting, receiveShadows);
    }

    private void OnDisable() {
    if (instancesBuffer != null) {
    instancesBuffer.Release();
    instancesBuffer = null;
    }
    if (argsBuffer != null) {
    argsBuffer.Release();
    argsBuffer = null;
    }
    }
    }