Graphics.RenderMeshIndirect
を利用することで、CPUを経由して描画するのではなく、GPUを直接利用して描画することができるため、大量の草などを軽く描画することができます
今回は10個の草を描画してみます
以下がスクリプトで、バッファを複数利用して描画処理を行っています
using UnityEngine; public class GrassRenderer : MonoBehaviour { [SerializeField] private Material _material; [SerializeField] private Mesh _mesh; private const int commandCount = 1; /// <summary> /// 描画用パラメータのバッファ /// </summary> private GraphicsBuffer _indirectBuf; /// <summary> /// 描画する座標等のデータ用バッファ /// </summary> private GraphicsBuffer _transformsBuf; /// <summary> /// Mesh 描画の設定 /// </summary> private GraphicsBuffer.IndirectDrawIndexedArgs[] _commandData; /// <summary> /// マテリアル等の設定 /// </summary> private RenderParams _renderParams; private static readonly int Matrix = Shader.PropertyToID("_GrassMatrix"); private void Start() { _renderParams = new RenderParams(_material) { worldBounds = new Bounds(Vector3.zero, 10000 * Vector3.one), matProps = new MaterialPropertyBlock() }; var transforms = new Matrix4x4[10]; for (var i = 0; i < transforms.Length; i++) { var position = new Vector3(i, 0f, 0f); var rotate = Quaternion.Euler(new Vector3(0f, Random.Range(0f, 360f), 0f)); transforms[i] = Matrix4x4.TRS(position, rotate, Vector3.one); } _transformsBuf = new GraphicsBuffer(GraphicsBuffer.Target.Structured, transforms.Length, 4 * 4 * sizeof(float)); _transformsBuf.SetData(transforms); _renderParams.matProps.SetBuffer(Matrix, _transformsBuf); _commandData = new GraphicsBuffer.IndirectDrawIndexedArgs[commandCount]; _commandData[0].indexCountPerInstance = _mesh.GetIndexCount(0); _commandData[0].baseVertexIndex = _mesh.GetBaseVertex(0); _commandData[0].startIndex = _mesh.GetIndexStart(0); _commandData[0].instanceCount = (uint)transforms.Length; _indirectBuf = new GraphicsBuffer(GraphicsBuffer.Target.IndirectArguments, commandCount, GraphicsBuffer.IndirectDrawIndexedArgs.size); _indirectBuf.SetData(_commandData); } private void Update() { Graphics.RenderMeshIndirect(_renderParams, _mesh, _indirectBuf, commandCount); } private void OnDestroy() { _transformsBuf?.Dispose(); _transformsBuf = null; _indirectBuf?.Dispose(); _indirectBuf = null; } }
こちらは Material に利用する Shader です
IndirectDrawIndexedArgs に対応している Shader じゃないと複数描画されないので注意してください
Shader "Custom/Grass" { SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #define UNITY_INDIRECT_DRAW_ARGS IndirectDrawIndexedArgs #include "UnityIndirect.cginc" struct v2f { float4 pos : SV_POSITION; float4 color : COLOR0; }; uniform StructuredBuffer<float4x4> _GrassMatrix; v2f vert(appdata_base i, uint instanceID : SV_InstanceID) { InitIndirectDrawArgs(0); v2f o; float4 wpos = mul(_GrassMatrix[instanceID], i.vertex); o.pos = mul(UNITY_MATRIX_VP, wpos); half v = instanceID / float(GetIndirectInstanceCount()); o.color = float4(0, v, 0, 0); return o; } float4 frag(v2f i) : SV_Target { return i.color; } ENDCG } } }