Metal 関係覚書

たまにしか使わないので基本概念が抜けがち。

シェーダー

具体的には ***.metal ファイルがそれ。
頂点データと色の処理を決めているファイル。これだけだと有り難みがピンとこないが、実際にはこれが(並列処理可能な) GPU で処理される、というのがミソ。
このおかげで、頂点が増えれば増えるほど、効率的な処理ができるようになる。

なお、この時、使用される言語が MSL (Matal Shading Language)。

Metal は OpenGL とは違い、***.metal ファイルはビルド時にプリコンパイルされれる(.metallib というファイルが生成される)。OpenGL では実行時にコンパイルされるので、この点も高速化に貢献してそう。

 

Metal 公式サンプル

アップルが公開している Metal の公式サンプルで気になったプロジェクトなど。

CAMetalLayer 関係

CA というのがわからなかったが、Core Animation のことらしい。
興味深くはあるが、私はあまり使わないかな。

Ray Tracing と InterSection を組み合わせたプロジェクト

綺麗だ。。。

が、ここら辺までくると文字ベースの解説は一切なし。
動画はあるけど。

2D texture 関係

特にサンプルは挙げられていないが、取り扱うデータによって何を採用したらいいのか?みたいなことがこの記事に書いてある。

具体的なサンプルとしては、とりあえず

https://developer.apple.com/documentation/metal/onscreen_presentation/reading_pixel_data_from_a_drawable_texture?language=objc

https://developer.apple.com/documentation/metal/textures/creating_and_sampling_textures?language=objc

の二つをチェック。

前者は、ビルドするとこんなウィンドウが表示される。

ドラッグすると、ドラッグした領域をデスクトップ上にファイルの形で切り出してくれる。
MTKView 上でマウスの位置に応じてちょっと工夫した処理を行いたい、なんてときに使えるかもしれない。

後者は、これ。

 

かなり以前からある基本的なプロジェクトでした。

が、今から思うとこれはこれで使い道ありそう。

(続く)

 

Metal がよくわからんという人は公式サンプルから入るといいと思う

以前に「Metal 入門」という記事を書いたことがあるのだが、Metal 関係の情報は乏しいせいかネット上ではかなり参照されているようだ。

放置するのもなんなので、先日、Metal を仕様する際に出てくる「コマンド」に関して追記した。

そこで提示したサンプルは Objective-C にするのか Swift にするのか迷ったのだが、結局、Swift にした。

じゃあ、Objective-C ではどうやるのってのが本記事。

Objective-C で書かれたサンプルは本当に少ないが、Objective-C から Metal を使いたい人は公式にあるサンプルあたりから入るといいと思う。

お馴染みの三角形を描くサンプルもある。

ただし、同一プロジェクトに iOS と tvOS のターゲットも同包されているので、MacOS だけ取り出しておいた方がわかりやすい。

こんな感じになる。

以下、このサンプルに関して注意点などメモ。

MTKView の設定

View は MTKView にする必要があるが、Xcode の操作性がイマイチで、手動で MTKView に設定する必要がある。

ViewPort

ところで、今回のサンプルでは、ウィンドウのサイズを変えても描画される三角形の大きさは変わらない。

これは ViewPort を使うことで以下のように実現している。

内部的には、ウィンドウに何らかの変化が起こると delegate の以下のメソッドが呼び出されている。

/// Called whenever view changes orientation or is resized
- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size
{
    // Save the size of the drawable to pass to the vertex shader.
    _viewportSize.x = size.width;
    _viewportSize.y = size.height;
}

要するに実際のウインドウのサイズを ViewPort のサイズとして引き渡しているわけですね。

この情報はシェーダーで以下のように処理されている。

    out.position.xy = pixelSpacePosition / (viewportSize / 2.0);

Metal の使用する座標系を実際のウィンドウの大きさで割ることで、描画する図形の大きさを一定に保っているという理屈です。

単純に三角形を描画させたいだけであれば、頂点のデータは

    static const PHVertex triangleVertices[] =
    {
        // 2D positions,    RGBA colors
        { {  1.0,  -1.0 }, { 1, 0, 0, 1 } },
        { { -1.0,  -1.0 }, { 0, 1, 0, 1 } },
        { {    0,   1.0 }, { 0, 0, 1, 1 } },
    };

などと Metal 本来の座標系に準じて設定。
シェーダーも

    //out.position.xy = pixelSpacePosition / (viewportSize / 2.0);
    out.position.xy = pixelSpacePosition;

としてしまえば、三角形はウィンドウの大きさに従って変化します。

描画色に変化をつけてみる

私は試してないが、『シェーダーにランダムな値を送って動きをつける』あたりを参照して、改変するといいと思う。

ソースコードはこちらで。

回転させる、遠近処理をつける

詳しい解説はしないが、それなりの改変を加えると回転や遠近処理もできる。

その入り口くらいまではこちらの記事で軽く説明しています。
よろしければご一読ください。