I’ve been working on a script to add instanced grass to my generated world in Unity, using a CommandBuffer and DrawMeshInstanced. Basically, I build my list of Matrix4x4’s and then run through the list in batches of 1023 to add each needed DrawMeshInstanced to my CommandBuffer. Finally, I call Graphics.ExecuteCommandBuffer, but nothing gets drawn.
If I check the frame debugger, I can see my commands in the list even though they don’t get drawn. Also, If I switch from using a CommandBuffer to just Graphics.DrawMeshInstanced, all works fine which confirms that I’m drawing everything where it should be.
Hoping someone can point me in the right direction, I’m using the Universal Render Pipeline/Simple Lit shader with GPU Instancing enabled on my material.
Here’s my code:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
namespace Genesis
{
public class InstancedGrass : MonoBehaviour
{
public Material material;
private List<Matrix4x4> _matrices = new List<Matrix4x4>();
private Server _server;
private World.Vegetation[,] _grasses;
private CommandBuffer _commandBuffer;
private Renderer _lod0;
private Mesh mesh;
void Start()
{
_server = GameObject.Find("Server").GetComponent<Server>();
_grasses = _server.world.Grasses;
_lod0 = gameObject.transform.Find("MeshHost_LOD0").GetComponent<Renderer>();
var chunkSize = _server.chunkSize;
_commandBuffer = new CommandBuffer();
_commandBuffer.name = gameObject.name;
// _commandBuffer.SetRenderTarget(RenderTargetIdentifier.AllDepthSlices);
var meshHostPos = transform.position;
mesh = CreateQuad();
for (int z = (int)meshHostPos.z; z < (int)meshHostPos.z + chunkSize; z++)
{
for (int x = (int)meshHostPos.x; x < (int)meshHostPos.z + chunkSize; x++)
{
if (_grasses[x, z] != null)
{
var position = new Vector3(x, _server.world.GetHeightAt(x, z) - 0.2f, z);
var rotation = Quaternion.Euler(0f, _grasses[x, z].rotation, 0);
var scale = new Vector3(_grasses[x, z].scale, _grasses[x, z].scale, _grasses[x, z].scale);
var matrix = Matrix4x4.TRS(position, rotation, scale);
_matrices.Add(matrix);
}
}
}
for (int index = 0; index < _matrices.Count; index += 1023)
{
int count;
if (index + 1022 < _matrices.Count)
{
count = 1023;
}
else
{
count = _matrices.Count - index;
}
_commandBuffer.DrawMeshInstanced(mesh, 0, material, -1, _matrices.GetRange(index, count).ToArray());
}
}
private void LateUpdate()
{
if (_lod0.isVisible)
{
Graphics.ExecuteCommandBuffer(_commandBuffer);
}
}
private Mesh CreateQuad()
{
Mesh mesh = new Mesh();
Vector3[] vertices = new Vector3[4]
{
new Vector3(0, 0, 0),
new Vector3(1, 0, 0),
new Vector3(0, 1, 0),
new Vector3(1, 1, 0)
};
mesh.vertices = vertices;
int[] tris = new int[6]
{
// lower left triangle
0, 2, 1,
// upper right triangle
2, 3, 1
};
mesh.triangles = tris;
Vector3[] normals = new Vector3[4]
{
-Vector3.forward,
-Vector3.forward,
-Vector3.forward,
-Vector3.forward
};
mesh.normals = normals;
Vector2[] uv = new Vector2[4]
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(1, 1)
};
mesh.uv = uv;
return mesh;
}
}
}
Thank you in advance to anyone who can point me in the right direction.