66 lines
2.6 KiB
C#
66 lines
2.6 KiB
C#
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
|
|
public class GPUGrassRenderer : MonoBehaviour
|
|
{
|
|
public Mesh grassMesh; // îäíà ìîäåëü òðàâèíêè (îäèí submesh)
|
|
public Material grassMaterial; // shader ìຠï³äòðèìóâàòè GPU instancing
|
|
public ComputeShader computeShader;
|
|
|
|
public int countX = 256;
|
|
public int countZ = 256;
|
|
public float sizeX = 50f;
|
|
public float sizeZ = 50f;
|
|
public float height = 0f;
|
|
|
|
GraphicsBuffer matricesBuffer;
|
|
GraphicsBuffer argsBuffer;
|
|
int totalCount;
|
|
|
|
void Start()
|
|
{
|
|
totalCount = countX * countZ;
|
|
|
|
// 1) create structured buffer for matrices (float4x4 = 16 floats = 64 bytes)
|
|
matricesBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, totalCount, 16 * sizeof(float));
|
|
// 2) args buffer (5 uints): indexCountPerInstance, instanceCount, startIndexLocation, baseVertexLocation, startInstanceLocation
|
|
uint[] args = new uint[5] { (uint)grassMesh.GetIndexCount(0), (uint)totalCount, (uint)grassMesh.GetIndexStart(0), (uint)grassMesh.GetBaseVertex(0), 0u };
|
|
argsBuffer = new GraphicsBuffer(GraphicsBuffer.Target.IndirectArguments, 1, sizeof(uint) * args.Length);
|
|
argsBuffer.SetData(args);
|
|
|
|
// dispatch compute to fill matrices
|
|
int kernel = computeShader.FindKernel("CSMain");
|
|
computeShader.SetInt("_CountX", countX);
|
|
computeShader.SetInt("_CountZ", countZ);
|
|
computeShader.SetFloat("_SizeX", sizeX);
|
|
computeShader.SetFloat("_SizeZ", sizeZ);
|
|
computeShader.SetFloat("_Height", height);
|
|
computeShader.SetBuffer(kernel, "matrices", matricesBuffer);
|
|
|
|
int threadGroups = Mathf.CeilToInt(totalCount / 64.0f);
|
|
computeShader.Dispatch(kernel, threadGroups, 1, 1);
|
|
|
|
// bind buffer to material for per-instance matrix access (if shader reads it)
|
|
grassMaterial.SetBuffer("matrices", matricesBuffer);
|
|
}
|
|
|
|
void OnDisable()
|
|
{
|
|
matricesBuffer?.Dispose();
|
|
argsBuffer?.Dispose();
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
// set render params: use simple bounds so Unity can cull
|
|
var bounds = new Bounds(transform.position, new Vector3(sizeX, 10f, sizeZ));
|
|
RenderParams rparams = new RenderParams(grassMaterial);
|
|
// the shader must use UNITY_INDIRECT_DRAW_ARGS / UnityIndirect.cginc if it needs instance id access
|
|
|
|
// call indirect draw
|
|
rparams.worldBounds = new Bounds(transform.position, new Vector3(sizeX, 10f, sizeZ));
|
|
Graphics.RenderMeshIndirect(rparams, grassMesh, argsBuffer);
|
|
// parameters: rparams, mesh, argsBuffer, commandCount=1, startCommand=0, worldBounds
|
|
}
|
|
}
|