【Unity】大量のテクスチャを表示する【RenderMeshInstanced】

# 概要
大量のテスクチャを表示したい時がある
例えば、ヴァンパイアサバイバーライクな2Dの敵が大量に出現する場合などが考えられる

https://www.docswell.com/s/DeNA_Tech/KEN3QR-2024-02-29-090246#p1

上記のスライドでは、そのようなゲームを実装する際のパフォーマンスチューニングについてわかりやすく説明している

気になったのがここのスライド
![スクリーンショット 2024-12-11 0.18.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/2fa81257-0b64-efa5-b22f-0a1daebd7072.png)

参考動画が貼られており、自分でも試せそうだと思ったので試してみた

# 実験
![スクリーンショット 2024-12-11 0.20.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/c7bdad85-3003-0e9d-b75e-79069a6feccc.png)
男の子の画像を用意した

この子をいっぱい表示することにする

動画では3Dだったが、今回はテクスチャを表示する四角のメッシュさえあればいいのでスクリプトで作ってしまう

```csharp:簡単なメッシュ生成
    void CreateMyMesh()
    {
        _myMesh = new Mesh
        {
            // 頂点は4つ
            // 2---0
            // |   |
            // 3---1
            vertices = new Vector3[]
            {
                new(1, 1, 0),
                new(1, -1, 0),
                new(-1, 1, 0),
                new(-1, -1, 0)
            },
            subMeshCount = 1,
            uv = new Vector2[]
            {
                new(1, 1),
                new(1, 0),
                new(0, 1),
                new(0, 0),
            }
        };

        _myMesh.SetTriangles(new[] { 0, 1, 3, 0, 3, 2 }, 0);
    }
```

描画には、GraphicsAPIにはDrawMeshなど低レベル高レベル様々なAPIが用意されている
動画では`Graphics.RenderMeshInstanced`を使っており、パターンによって`Graphics.RenderMesh`がいいそう

```csharp:描画部分
for(var offs = 0; offs < matrices.Length; offs += 1023)
{
    var count = Mathf.Min(1023, matrices.Length - offs);
    Graphics.RenderMeshInstanced(rparams, _myMesh, 0, matrices, count, offs);
}
```
ひとまず動画の最終系通りに実装してみる

![スクリーンショット 2024-12-11 0.30.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/0c5b7e21-cea5-b3b3-aff1-9b4a8b6707ad.png)

大量に表示することができた

歩かせたりもしてみる

![画面収録 2024-12-11 0.33.37.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/390183a1-0bc4-17e0-65ee-bfacde3dd700.gif)

撮影時は100FPSほどだが、撮影を止めると300FPSぐらい出ていた

プロファイラで見るとUpdate()に0.07msかかっている
![スクリーンショット 2024-12-11 0.38.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/cc93c9e9-e3e5-fe54-a1b1-2d49d0fa07bc.png)

試しにRenderMeshを使ってみる

```csharp:RenderMeshを使ってみる
for(var offs = 0; offs < matrices.Length; offs++)
{
    Graphics.RenderMesh(rparams, _myMesh, 0, matrices[offs]);
}
```
動かしてみると...

![スクリーンショット 2024-12-11 0.40.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/2a4bd785-fd74-98fb-5638-f8dfb40cfff2.png)

Updateに0.17msかかっている
確かにRenderMeshInstancedの方がパフォーマンスに良さそう

# もっと表示させてみよう
試しに500*500の250000個表示してみる

![スクリーンショット 2024-12-11 0.42.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/dce537f0-22e1-977d-64d6-55a1ddf1910e.png)

### RenderMesh
![スクリーンショット 2024-12-11 0.43.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/e103c5d8-6220-1f11-1f46-b9337111134c.png)

![スクリーンショット 2024-12-11 0.43.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/6047153b-4b29-94ba-9a1c-53c4ac60ae16.png)


### RenderMeshInstanced

![スクリーンショット 2024-12-11 0.45.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/2edb44d9-73de-d6fd-844d-55b4cfe1b1a4.png)

![スクリーンショット 2024-12-11 0.44.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/1eca42cf-1f60-5fe8-5c24-f234a482c08d.png)

顕著な差が出た
カメラ外のテクスチャをカリングするようにすればRenderMeshの方が有利になるかもしれない

今度試してみる