おはようございます。モノトーンです。
今日は,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]
は vertexBuffer
の atIndex: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 やってない人しかわかりにくい説明になりましたが,日本語での解説がないことや,レイアウトなんてテキトーでも動くだろ( みたいな俺みたいな人向けのメモ書きです。