MetalKitのSwift版サンプル

元ネタのApple公式のMetalKitEssentialsをSwiftで書き直し+αしたもの。 内容は主にMetalKitを使って、obj形式のモデルをテクスチャありで表示させるだけ。 シェーダもいたってシンプルでライトもなし。
ちなみに、MetalKitはiOS9以降でしか使えないので注意。

小ネタ

はじめに

一番最初につまずいたのは、ビルド自体が通らず、Metalのフレームワークのインポートでエラーになる!ってこと。当然、コードを書く時にも自動補完は効かないしエラーでまくるし・・・
で、原因はターゲットでシュミレータを選択していたこと。実行できないのは知っていたけど、まさかビルドすら通らないのは予想外。。。

バッファへのアクセス

今回、一番書き方が判らなくて苦労したのがこれ。単にVertexBufferへのポインタを取得して、中のデータを読み書きしたいだけなのだが、当然、Swiftがメモリへの直アクセスを許してくれるわけはなく・・・

上がObjective-Cで書いた場合で下がSwiftの場合:

Swiftでは、まずポインタpを明示的に取得し、それからmemory()VertexUniformsの型へ変換し、それを通して中のデータへアクセスするという手間が必要。やはりSwiftは型にうるさい。

なお、このサンプルでは配列ではないのでp.memory()だが、バッファの内容が配列になっていてインデックスでアクセスしたい場合は、p.advancedBy(i).memory()(iがインデックス)とする。

ちょっと面倒だけど、暗黙的な「わかる人にはわかる」といった曖昧さを排除し、ポインタの状態やメモリにアクセスしていることを明示させているのは、Swiftの良さの一つだと思う。

シェーダ用の構造体

今回、シェーダにデータを渡す時の型(構造体)を、シェーダのファイルとSwift上でそれぞれ同じ宣言をしている。これは、Swiftから直接Cのファイルを見に行けない為。ブリッジヘッダを使ったりすれば重複して宣言しなくてよさそうだけど、未検証。Swift上ではSwiftの構造体を使えた方が便利かなと思ったので(結局使わなかったけど)

なお、当然ながらメモリのアライメントには注意が必要(公式:アライメント一覧)なので、必要に応じてパディングすること。ちなみに忘れると画面が心霊現象みたくなったり表示されなかったり・・・

SIMD

Xcode7からようやくSIMDがサポート。これでvectorやmatrixのベタなコードを書く or 持ってくる必要がなくなった。(でも移動や回転とかはやっぱり自前が必要)

import simdで使えるようになる。MetalKitのインポートでも良い。

感想

正直なところ、Unityとかに慣れてしまった身にとって、Metalは結構大変だった。。。日本語の資料も少ないし、公式の資料もまだまだObjective-Cが多い感じ。
といっても、DirectXのダラダラとした初期化とかに比べると、機種依存がなく簡潔で楽。久々に3Dの基礎を振り返る良い機会になったと思う。
結局まあ、Unityとかが偉大すぎるという当たり前の結論に到達。

触っていて、良い!と思ったのは、バグで描画がおかしくなったりしても、影響が端末だけに限られて作業しているMacは無事なこと。
昔々のDirectXでしょっちゅうブルースクリーンを出してしまい、コードが消えたりPC不安定になっていた人なので、これはとても助かった。

開発環境

ソース

こちら (iOS9 A7以降搭載機種のみ)