using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; public class Grass : MonoBehaviour { public Mesh mesh; public Material material; public Bounds bounds; public float scaleMult; public ShadowCastingMode shadowCastingMode; public bool isReceiveShadow; public Vector3 objectBoundMin; public Vector3 objectBoundMax; public ComputeShader computeShader; int kernel = 0; ComputeBuffer instDataBuffer; ComputeBuffer cullIDsBuffer; ComputeBuffer argsBuffer; public Transform root; List dataInfors = new List(); private struct InstData { public Vector3 pos; public Vector3 angle; public Vector3 scale; // public static int GetNum() { return sizeof(float) * 3 + sizeof(float) * 3 + sizeof(float) * 3; } } private void Start() { GetDataInfors(); InitializeBuffers(); } void GetDataInfors() { foreach (Transform t in root.GetComponentInChildren()) { InstData instData = new InstData(); instData.pos = t.position; instData.angle = t.eulerAngles; instData.scale = t.localScale * scaleMult; dataInfors.Add(instData); // t.gameObject.SetActive(false); } } private void InitializeBuffers() { // Arguments for drawing mesh. uint[] args = new uint[5] { 0, 0, 0, 0, 0 }; // 0 == number of triangle indices, 1 == count, others are only relevant if drawing submeshes. args[0] = (uint)mesh.GetIndexCount(0); args[1] = (uint)dataInfors.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); // Initialize buffer with the given population. material = Instantiate(material); instDataBuffer = new ComputeBuffer(dataInfors.Count, InstData.GetNum()); instDataBuffer.SetData(dataInfors); material.SetBuffer("_InstDataBuffer", instDataBuffer); cullIDsBuffer = new ComputeBuffer(dataInfors.Count, sizeof(uint), ComputeBufferType.Append); material.SetBuffer("_CullIDsBuffer", cullIDsBuffer); // computeShader = Instantiate(computeShader); kernel = computeShader.FindKernel("CSMain"); computeShader.SetBuffer(kernel, "_InstDataBuffer", instDataBuffer); computeShader.SetVector("_BoundMin", objectBoundMin); computeShader.SetVector("_BoundMax", objectBoundMax); computeShader.SetBuffer(kernel, "_CullIDsBuffer", cullIDsBuffer); } private void Update() { cullIDsBuffer.SetCounterValue(0); computeShader.SetVectorArray("_FrustumPlanes", GpuCullCamera.inst.frustumPlanes); computeShader.Dispatch(kernel, Mathf.CeilToInt(dataInfors.Count / 128f), 1, 1); ComputeBuffer.CopyCount(cullIDsBuffer, argsBuffer, sizeof(uint)); // Graphics.DrawMeshInstancedIndirect(mesh, 0, material, bounds, argsBuffer, 0, null, shadowCastingMode, isReceiveShadow, LayerMask.NameToLayer("Instance")); } private void OnDrawGizmos() { Gizmos.color = Color.blue; Gizmos.DrawWireCube(bounds.center, bounds.size); } private void OnDisable() { // Release gracefully. if (instDataBuffer != null) { instDataBuffer.Release(); } instDataBuffer = null; if (cullIDsBuffer != null) { cullIDsBuffer.Release(); } cullIDsBuffer = null; if (argsBuffer != null) { argsBuffer.Release(); } argsBuffer = null; } }