Files
ScienceLab.Density/Assets/Scripts/Lesson_1/GPUGrassInstancing.cs
2026-06-04 00:55:54 +03:00

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
}
}