159 lines
3.8 KiB
C#
159 lines
3.8 KiB
C#
|
|
|
||
|
|
|
||
|
|
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<InstData> dataInfors = new List<InstData>();
|
||
|
|
|
||
|
|
|
||
|
|
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<Transform>())
|
||
|
|
{
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
}
|