日本語が少ないのはいいんだけど、英語の記事もなんだか少なくて細かいところがわかりづらくて四苦八苦。
基本的なUniform変数の取り扱いも若干手間取ったのでメモ。
データの準備
「iOSの新グラフィックAPI - Metal入門してみる」でも書いたけど、Metalの特徴としてCPUとGPUのメモリ共有があります。
なので、データの準備がかなり楽にできます。こんな感じ↓
type-define
struct AnyUniforms {
bool useHoge;
float size;
float offset[2];
};
まずはこんな感じで構造体を定義します。
これをなにがしかのヘッダファイルで宣言しておき、ObjC側とシェーダ側双方に読み込ませます。
ObjC側の準備
id <MTLBuffer> buffer = [device newBufferWithLength:sizeof(struct AnyUniforms)
options:MTLResourceOptionCPUCacheModeDefault];
struct AnyUniforms *circleBuf = (struct AnyUniforms*)[buffer contents];
buffer->useHoge = YES;
buffer->offset[0] = 0.5;
buffer->offset[1] = 0.5;
buffer->size = 0.35;
準備はこんな感じで行います。
バッファを取得して直に値を設定します。
GPUに送信
GPU側に伝えるにはMTLRenderCommandEncoderのsetFragmentBuffer:offset:atIndex:
メソッドを使って伝えます。
[renderEncoder setFragmentBuffer:buffer offset:0 atIndex:0];
シェーダでデータを使う
送られたデータは以下のようにして使うことができます。
fragment half4 frag(VertexOut input [[stage_in]],
constant AnyUniforms &any_uniforms [[buffer(0)]]) {
if (any_uniforms.useHoge) {
// ...
}
}
OpenGLのバインド的な処理がなくて非常に分かりやすくデータを扱えるのがいいですね。