Graphics.DrawMeshInstanced
Draws the same mesh multiple times using GPU instancing.
GPU instancingを利用して同一メッシュのインスタンスを複数回描画できる。
- 各インスタンスのTransformation情報は
Matrix4x4
の配列で指定する。 -
MaterialPropertyBlock
でインスタンスごとのデータを設定できる。 - 一度に描画できるインスタンス数は1023個まで。
- マテリアルの
Material.enableInstancing
をtrueに設定しておく必要がある。
実際に試す
メッシュにQuadを指定、GPU Instancingに対応したマテリアルを用意して以下のコードを実行する。
(マテリアルに使用したシェーダーは後述。)
TestDrawMeshInstanced01.cs
using UnityEngine;
namespace TestGPUInstancing
{
public class TestDrawMeshInstanced01 : MonoBehaviour
{
[SerializeField] private Mesh _mesh;
[SerializeField] private Material _material;
private const int MeshCount = 1023;
private Matrix4x4[] _matrices;
private void Start()
{
_matrices = new Matrix4x4[MeshCount];
for (int i = 0; i < MeshCount; i++)
{
var pos = new Vector3(
UnityEngine.Random.Range(-10f, 10f),
UnityEngine.Random.Range(-10f, 10f),
UnityEngine.Random.Range(-10f, 10f)
);
_matrices[i] = Matrix4x4.TRS(pos, Quaternion.identity, Vector3.one);
}
}
private void Update()
{
Graphics.DrawMeshInstanced(_mesh, 0, _material, _matrices);
}
}
}
結果は以下の通り。
Batches
が5と非常に少なくなっており、バッチが効いていることがわかる。
インスタンス毎に色を変える
上述の通りMaterialPropertyBlock
を用いてインスタンス毎にプロパティを設定できる。
色を設定するためにSetColor
とうい関数が用意されているが、これだと全インスタンスが同一カラーになってしまう。インスタンス毎に色を指定したい場合は、SetVectorArray
を用いる。
TestDrawMeshInstanced02.cs
using UnityEngine;
namespace TestGPUInstancing
{
public class TestDrawMeshInstanced02 : MonoBehaviour
{
[SerializeField] private Mesh _mesh;
[SerializeField] private Material _material;
private const int MeshCount = 1023;
private Matrix4x4[] _matrices;
// MaterialPropertyBlockを使用してインスタンス毎にプロパティを設定できる
private MaterialPropertyBlock _propertyBlock;
private void Start()
{
_matrices = new Matrix4x4[MeshCount];
_propertyBlock = new MaterialPropertyBlock();
var colors = new Vector4[MeshCount];
for (int i = 0; i < MeshCount; i++)
{
var pos = new Vector3(
UnityEngine.Random.Range(-10f, 10f),
UnityEngine.Random.Range(-10f, 10f),
UnityEngine.Random.Range(-10f, 10f)
);
_matrices[i] = Matrix4x4.TRS(pos, Quaternion.identity, Vector3.one);
var r = i / (float)MeshCount;
var g = 1f - i / (float)MeshCount;
colors[i] = new Vector4(r, g, 0f, 1f);
}
_propertyBlock.SetVectorArray("_Color", colors);
}
private void Update()
{
Graphics.DrawMeshInstanced(_mesh, 0, _material, _matrices, MeshCount, _propertyBlock);
}
}
}
1024個以上のインスタンスを描画する。
上述の通り、Graphics.DrawMeshInstancedで
一度に描画できるインスタンス数は1023個が上限。それ以上のインスタンスを描画する場合は自前でバッチすればOK。
TestDrawMeshInstanced03.cs
using System.Collections.Generic;
using UnityEngine;
namespace TestGPUInstancing
{
public class TestDrawMeshInstanced03 : MonoBehaviour
{
[SerializeField] private Mesh _mesh;
[SerializeField] private Material _material;
private int MeshCount = 1023 * 4;
private List<Matrix4x4[]> _batches;
private void Start()
{
_batches = new List<Matrix4x4[]>();
var matrices = new Matrix4x4[1023];
for (int i = 0; i < MeshCount; i++)
{
if (i % 1023 == 0)
{
matrices = new Matrix4x4[1023];
_batches.Add(matrices);
}
var pos = new Vector3(
UnityEngine.Random.Range(-10f, 10f),
UnityEngine.Random.Range(-10f, 10f),
UnityEngine.Random.Range(-10f, 10f)
);
matrices[i % 1023] = Matrix4x4.TRS(pos, Quaternion.identity, Vector3.one);
}
}
private void Update()
{
foreach (var batch in _batches)
{
Graphics.DrawMeshInstanced(_mesh, 0, _material, batch, 1023);
}
}
}
}
結果。
使用したShader
ShaderはGPU Instancingに対応させる必要がある。この辺は凹みさんの記事を参考。
.shader
Shader "Unlit/GPUInstanceTest"
{
Properties
{
_Color ("Color", Color) = (1, 1, 1, 1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float4 vertex : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
UNITY_INSTANCING_BUFFER_START(Props)
UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
UNITY_INSTANCING_BUFFER_END(Props)
v2f vert(appdata v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_TRANSFER_INSTANCE_ID(v, o);
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(i);
return UNITY_ACCESS_INSTANCED_PROP(Props, _Color);
}
ENDCG
}
}
}
参考