Skip to content

Instantly share code, notes, and snippets.

Created March 3, 2022 05:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sir-hc-daudore/51c6bfc7bdfbf8e806680b0c05d074aa to your computer and use it in GitHub Desktop.
Save sir-hc-daudore/51c6bfc7bdfbf8e806680b0c05d074aa to your computer and use it in GitHub Desktop.
Rendering many meshes using GPU instancing
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// Class for drawing meshes using the Graphics.DrawMeshInstanced method.
// At initialization, generates a list of transform matrices,
// each representing an object and its position.
// During update steps, it sends draw requests for the objects using
// Graphics.DrawMeshInstanced and providing the meshes' transform matrix array.
public class InstanceRenderer : MonoBehaviour
// Unity defines a hard lmit for the amount of meshes drawn per DrawMeshInstanced call
// Limit is between 0 and 1023
private const int MAX_MATRIX_ARRAY_SIZE = 512;
private Vector2 fieldSize = new Vector2(50, 50);
private float densityPerMetre = 1;
[SerializeField, Min(0.0f)]
private float positionOffset = 0.2f;
private Mesh baseMesh;
private Material material;
// Stores batches of object transforms, each of maximum size of MAX_MATRIX_ARRAY_SIZE
// Each matrix transform represents an object and its position, rotation and scale
private List<Matrix4x4[]> matrixList;
void Start()
matrixList = new List<Matrix4x4[]>();
// A matrix block will contain each transform for the meshes
List<Matrix4x4> matrixBlock = new List<Matrix4x4>();
Vector3 baseOffset = -new Vector3(fieldSize.x, 0, fieldSize.y) / 2.0f;
// Iterate through x position
for (float x = 0; x < fieldSize.x; x += densityPerMetre)
// Iterate through z position
for (float z = 0; z < fieldSize.y; z += densityPerMetre)
// Lets get some noise for adding some variation to the meshes
float noise = Mathf.PerlinNoise(x, z);
// Calculate position and rotation for the object
Vector3 basePosition = new Vector3(x, 0, z);
float zRot = 360f * noise;
Quaternion rotation = Quaternion.Euler(0, zRot, 0);
Vector3 posOffset = rotation * (noise * positionOffset * Vector3.forward);
// Build a transform matrix with the position, rotation and scale,
// and add it to the matrix block
matrixBlock.Add(Matrix4x4.TRS(basePosition + baseOffset + posOffset, rotation,;
// Once the matrix block fills for the max size, add it to the list of matrix arrays,
// and prepare a new block for the next objects
if (matrixBlock.Count >= MAX_MATRIX_ARRAY_SIZE)
matrixBlock = new List<Matrix4x4>();
private void Update()
// Iterate for each matrix array
for(int i = 0; i < matrixList.Count; i++)
// Attributes: mesh to render, submesh to use from the mesh,
// material used for rendering, and matrix array containing each of the object transforms.
Graphics.DrawMeshInstanced(baseMesh, 0, material, matrixList[i]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment