3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

UnityAdvent Calendar 2023

Day 4

【Unity】Draw indirect argument buffer too small. Must be at least XX bytes というエラーが出たときの対処法【ConputeShader】

Last updated at Posted at 2023-12-03

本記事は Unity Advent Calendar 2023 4日目の記事です。
3日目:CanvasMaterialでUI Shaderをシンプルに @up-hash さん << ココ >> 5日目:unsafeでアンマネージドな構造体でポインタアクセスとポリモーフィズムのテスト @fukaken5050 さん

TL;DR

  • ComputeShader/ComputeBuffer を使う時はUnityのサンプルを読もう
  • ComputeShader/ComputeBuffer 周りはググってもChatGPTも答えてくれないことが多いので、覚悟を持って挑もう
  • C#のここの行がエラーとは示さないのでエラー文から原因を推測する力が必要です

エラーの経緯

業務て点群のデータ(.ply, .e57等) をUnityで読めるプログラムを制作している際、Particleとして点群を描画するため Graphics.DrawMeshInstancedIndirect関数 を使っていました。

Mac (Editor / MacOS App) では問題なく表示できたのですが、Windows 環境 (Editor/App) では Draw indirect argument buffer too small. Must be at least 20 bytes (5ints). という謎のエラーが表示され、点群が描画できないという事象にぶつかりました。

もちろんググっても英語のページすらヒットしない状況。

ChatGPT に聞いても
スクリーンショット 2023-11-29 15.54.48.png
といった具合に当たり障りのない、ちょっと気を利かせた翻訳程度くらいの情報しか得られません。

エラーの原因

Graphics.DrawMeshInstancedIndirect API では引数に Mesh情報, Material情報, 'ComputeBuffer` 等が要求されます。

この ComputeBuffer ですが、GPGPUに日常的に触れている方いがいはほとんど馴染みのないClassだと思います。
ここのComputeBufferの設定パラメータミスによって今回のエラーが発生していることがわかりました。

ComputeBuffer

ComputeBuffer は名前の通りComputeShader で読み書きするようのデータ置き場のことです。

ComputeBufferはコンストラクタで初期化するのですが、そのときの引数として以下の情報を与える必要があります。

パラメータ名 説明
count Bufferに格納する要素数。 1: スカラー, 1次元配列, 2: 2次元配列 ...
stride Bufferに格納される要素1つあたりのサイズ[byte]
ただし2048 未満の4の倍数、つまりは int/uint/float =4byte * 配列長さ の値を入れればOK
type [Buffer の種別定義](https://docs.unity3d.com/ScriptReference/ComputeBufferType.html
DrawMeshInstancedIndirect を使う場合は ComputeBufferType.IndirectArguments 一択
usage 省略可能. Bufferの利用用途定義

ここのstrideは基本的に事前に作成した int[]/uint[]/float[] のLength * sizeof(int)/sizeof(uint)/sizeof(float) って感じでやれば問題ないです。

Draw indirect argument buffer too small. Must be at least XX bytes

エラー文の字のごとく、Bufferサイズが小さいというエラーです。

今回は Must be at least 20 bytes (int5s) とあり、int[5]以上のBufferがないといけないとのことでした。

ComputeBuffer.cs

void Initialize()
{
    ...

    
    var args = new uint[4]
    {
        particleMesh.GetIndexCount(0),
        (uint) particles.Length,
        particleMesh.GetIndexStart(0),
        particleMesh.GetBaseVertex(0),
    };
    var argBuffer = new ComputeBuffer(
        1,
        sizeof(uint) * args.Length,
        ComputeBufferType.IndirectArguments
    );
    argBuffer.SetData(args);

    ...
}

みたいな形で必要なパラメータをargs変数に定義してそれを渡していたのですが、どうやら動かすプラットフォームによって必要な最小バッファサイズが異なるようです。

MacOSXであれば問題なく描画できたのですが、Windowsだと描画に失敗しました。

ちなみに Graphics.DrawMeshInstancedIndirect のサンプルを見てみると

Graphics.DrawMeshInstancedIndirect.Sample.cs


    private int cachedInstanceCount = -1;
    private int cachedSubMeshIndex = -1;
    private ComputeBuffer positionBuffer;
    private ComputeBuffer argsBuffer;
    private uint[] args = new uint[5] { 0, 0, 0, 0, 0 };

のように利用しなくても、 uint[5] で定義しているので、基本的にはサンプルに則って作っておくのがよさそうです。

まとめ

  • ComputeShader/ComputeBuffer を使う時はUnity公式のサンプルをしっかり観察しよう
  • ComputeShader/ComputeBuffer 周りはググってもChatGPTも答えてくれないことが多いので、覚悟を持って挑もう
  • C#のここの行がエラーとは示さないのでエラー文から原因を推測する力が必要です
    • 今回だと描画ができない→Shader系
    • DrawIndirectの文字がある→ShaderコードではなくAPIを呼んでいる箇所
    • buffer 5ints とある→過去に動いていたコードと比較してint配列に差分がないか確認
      • あたりだった
3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?