モノトーンの伝説日記

Apex Legends, Splatoon, Programming, and so on...

<mini> Metal と MTLBuffer と attribute(n)

 おはようございます。モノトーンです。

 今日は,Metal の知見について軽くまとめようと思ってます。

Vertex Shader, Fragment Shader

 3DCG 関連を触ったことがある方ならわかると思いますが,Vertex Shader と Fragment (Pixel) Shader という大きな 2 つのシェーダーの枠組みがあります。今回は Metal における Vertex Shader のお話。

 Vertex Shader は [[stage_in]] には任意のデータを転送することが可能です。このデータは MTLVertexDescriptor で細かく指定できます。例えば,1 つの MTLBuffer に複数のデータを押し込み,適切に MTLVertexDescriptor を指定することによって正しく Metal 側で解釈できます。

 このとき,構造の [[attribute(n)]]MTLVertexDescriptor.attributes[n] は対応しており,bufferIndex, offset, format を適切に指定してやれば OK です。また,MTLVertexDescriptor.layouts[n]vertexBufferatIndex:n で転送したデータと対応しており,これは上で説明した bufferIndex にも対応しています。

 ややこしいですが,これらの転送 index と Descriptor は一致する必要があります。

 一方で,[[buffer(n)]] で指定されるデータは MTLVertexDescriptor で指定してはいけません。これを指定していると Unused buffer at index 0 とか言った assertion メッセージがでます。

 言葉で説明するとややこしいのでもう一度まとめると,(X が入っている場合,それが対応する値)

  • MTLVertexDescriptor.attributes[X] = [[attribute(X)]]
  • MTLVertexDescriptor.attributes[n].bufferIndex = setVertexBuffer:buffer atIndex:X = MTLVertexDescriptor.layouts[X]

 個人的にメモリたいのは,Vertex Shader における MTLVertexDescriptor に書くべき内容は [[stage_in]] に使用する構造体のレイアウトのみを指定し,他の [[buffer(n)]] で渡す構造体はレイアウトを渡さなくて良い,という知見でした。

 若干ハマったのと,Metal やってない人しかわかりにくい説明になりましたが,日本語での解説がないことや,レイアウトなんてテキトーでも動くだろ( みたいな俺みたいな人向けのメモ書きです。