趣味のプログラミング(2)
「趣味のプログラミング(1)」の続きです。
2024年2月1日
先月に引き続き、サンプル・アプリ「Depth Testing」をベースにしたテンプレート・プロジェクトを使って、Metal の座標系について確認します。サンプル・アプリ「Depth Testing」のオリジナル・コードでは、描画領域の左上を原点にピクセル単位で描画する頂点データをMetal コードへ渡し、Metal コード側で、ネイティブの座標系に変換していました。
一旦、Metal コード側の座標変換を無しにして、ネイティブの座標系を使っての描画を確認しました。
次のソースコードは、『{{ X座標, Y座標, Z座標 }, { 描画色 }}』を一つの頂点データとし、白、赤、緑、青の四つの三角形を描画するための12個の頂点データを示します。
これらの頂点データを使って描画した結果が次の通りです。
このMetal ネイティブの座標系は、表示されている描画領域の縦横(X,Y)の中心を原点(0,0)として、左上が(-1,1)、右下が(1,-1)になっていました。
2024年2月2日
昨日の続き、Metalのネイティブ座標系は、表示されている描画領域に対する相対的な座標のため、描画領域のサイズが変わったり縦横比が変わると、描画内容も合わせて変わってしまいます。
続いて、サンプル・アプリ「Depth Testing」のオリジナルのMetalコードに戻して、描画領域の左上を原点にしたピクセル単位で描画するよう座標変換して描画します。
次のソースコードは、昨日同様に『{{ X座標, Y座標, Z座標 }, { 描画色 }}』を一つの頂点データとし、白、赤、緑、青の四つの三角形を描画するための12個の頂点データを示します。座標をピクセル単位に変更しています。
このように座標変換して描画すると、描画領域のサイズが変わったり縦横比が変わっても、描画内容のサイズを維持することができます。
Metalのネイティブ座標系を使って描画するか、座標変換し描画サイズを維持して描画するかは、アプリケーション次第ですね。
2024年2月3日
これまで本家開発者向けサイトで Metal について色々と確認してきて、いよいよ、アプリとGPUとのインタフェースを担う Metal シェーディングのコーディングに取り組もうと、そのあたりの仕様の詳細を探していたら、次のページを発見してしまいました。
このページは、これまで確認していた Metal フレームワークの解説ページの上位のベージで、より広い視点での Metal フレームワークの概要紹介が行われていました。そして、このページの一部に以前から確認していた解説ページへのリンクもあり、本来、最初にチェックすべきMetal フレームワークのトップページは、このページだった事を今更ながら、気付いてしまいました。
ということで、改めてこのページを確認しておきたいと思います。
2024年2月4日
昨日から探していた Metal シェーディングのコーディング仕様は、『Metal Shading Language Specification Version 3.1』のPDFファイルで公開されていました。
この仕様書に目を通して、以下の点について再認識することができました。
・Metalシェーディング言語(Metal Shading Language)は、略称で「MSL」と呼ばれること。
・Xcodeプロジェクトに含まれる(シェーディング・コードを記述している) Metal ファイルは、Objective-C で書かれていると認識していたが、実際は、MSLで、「C++14」をベースにしている Metal のためのプログラミング言語であること。
・Metal コードでは、C++の標準ライブラリが使えず、独自の標準ライブラリを使用すること。
・Metal では、レンダリングを行う各段階で、グラフィックスデータを表現するために以下のような座標系が定義されていること。
①4次元均質ベクトル(four-dimensional homogenous vector)(x, y, z, w) は、クリップ空間座標(clip-space coordinates)の3次元座標を指定している。Metal は、x、y、およびzの値をwで割って、クリップ空間座標を正規化されたデバイス座標(NDC / normalized device coordinates)に変換している。
②正規化されたデバイス座標(NDC)は、左手座標系を使用しビューポート内にマップしている。これらの座標はビューポートのサイズには依存せず、ビューポートの左下隅は (x, y) 座標(-1.0, -1.0) にあり、上隅は(1.0, 1.0) にあること。z の正の値は、カメラから離れたところを指していて、Z座標の可視部分は 0.0 から 1.0 の間であること。
③ラスタライズする段階では、正規化デバイス座標(NDC)をビューポート座標に変換していること。この座標空間の (x, y) 座標はピクセル単位で測定され、原点はビューポートの左上隅にあり、正の値は右と下になること。この座標空間でビューポートを指定し、Metal は NDC座標をビューポートの範囲にマッピングしていること。他に「可変ラスタライズ」という機能があること。
④テクスチャ座標は、ビューポート座標に同様の座標系を使用すること。テクスチャ座標は、正規化されたテクスチャ座標を使用して指定することもできること。2Dテクスチャの場合、正規化されたテクスチャ座標は、x 方向と y 方向の両方で0.0から1.0までの値となること。
これらの座標系のうち、昨日(2024年2月3日)までに確認した座標系は、デバイス座標(NDC / normalized device coordinates)ということになりそうです。ただ、このようにいくつかの座標系が定義されていると、一概に Mac の Metal フレームワークの座標系は、〇〇ですと言い切れないもどかしさが残ります。😆
なんとか、MSLの仕様書も参照できるようになったので、直方体描画のための (Metal シェーディングの)コーディングを進めていきたいと思います。😅
2024年2月5日
昨年までに Microsoft C# で作成していた3D描画のシェーディング・コードをMetal 版に移植し、線分のみでの直方体の描画を実装してみました。
サンプル・アプリ「Depth Testing」で使われていた三つのスライダーは、それぞれ、X軸、Y軸、Z軸の回転用に転用しています。
この段階では、まだ奥行きの圧縮を適用していません。
2024年2月6日
線描画から、三角形を用いた直方体の描画へ変更してみました。Metal の深さのテストにより、自動的な隠面処理が行われています。
三角形を用いた直方体の描画に線分の描画を加えてみました。
Metal のZ軸の可視範囲が 0.0 から 1.0 の範囲のため、0.0 より前面に描画しようとすると、はみ出した部分がカットされ、そこから内部が覗けてしまいます。😣
2024年2月7日
直方体描画の配色や、スライダーのレイアウトを調整しようと思いましたが、スライダーの位置の変更が思った通りにできません。Xcode のストリーボードの編集に慣れるには、時間がかかりそうです。😆
Z軸の回転機能については、視覚的に地味だったので無しにしました。
どうやら、次のサイトによると、Storyboard を使った開発は旧式のようで、現行は、SwiftUI開発へシフトしてきているとのこと。また、現在、テンプレートにしているプロジェクトでは Storyboard を使っているので、SwiftUI へ切るかえるかどうか悩みが増えてしまいました。😣
2024年2月8日
Objective-C +Storyboard ベースのプロジェクトをSwiftUI ベースのプロジェクトへ移行中。😔
2024年2月9日
引き続き、Objective-C +Storyboard ベースのプロジェクトをSwiftUI ベースのプロジェクトへ移行中。😞
2024年2月10日
まだまだ手探り感が強い感じで、ようやく、直方体を描画する段階までを、SwiftUI ベースのプロジェクトへ移行。テンプレートにした SwiftUI のプロジェクトの名残で、(何ら機能しない)Start ボタンが付いていますが、回転させるためのスライダーも手探りしながら、追加していきたいと思います。😅
ようやく、二本のスライダーを追加しました。Y軸方向の回転用のスライダーを右端の縦に配置しようとあれこれ試してみましたが、実現方法を見出せませんでした。やむなく、右端縦方向でのスライダー配置は一旦保留しました。☹️
本家開発者向けサイトのサンプルコードが Objective-C 実装で、読み解くために Objective-C を勉強して、しばらくは Objective-C で進めようという気持ちになりましたが、結局は、画面レイアウトの課題で、早くも Swift へ戻ってしまいました。しかしながら、SwiftUI での画面レイアウトも簡単ではないので、まだまだ苦労しそうです。
次の段階としては、 CoreAnimation フレームワークを使った直方体描画にトライしてみたいと思います。😣
2034年2月11日
CoreAnimation フレームワークのサンプルコードを探して、本家開発者向けサイトを彷徨っていましたが、なかなか見出すことができませんでした。
いまさらですが、真剣に目を通すことが無かった『本家開発者向けサイトのトップページ』から、見直してみました。
さまざまな製品やサービスのアプリ開発プラットフォームが紹介されています。
このトップページから、開発者向けドキュメントを探すには、ページの下部にある『ドキュメント』の『ドキュメントを読む(英語)』または『日本語ドキュメント』のリンクから、ドキュメントの紹介ぺージを開きます。
日本語ドキュメントに期待するドキュメントが見当たらない場合は、『ドキュメントを読む(英語)』のリンクを開きます。
『Featured』のページが開かれるので、ページトップの右端の『Technologies』のリンクをクリックすると、ドキュメントの検索ページへ移動します。
このページから、キーワードを指定しドキュメントが検索できます。
今回、3D描画についてのドキュメントを検索するために、キーワードに『3D』を指定し検索します。現時点で検索された結果は、以下の15件でした。
(1) Metal
これまで、確認してきた Metal フレームワーク。
(2) Model I/O
MetalKit、GLKit、SceneKitを統合した共通の基盤を使用して、3Dモデルをインポート、エクスポート、そして操作を行う Model I/O フレームワーク。このフレームワークについても、適用を検討してみたいと思います。
(3) OpenGL ES
(非推奨となっている) OpenGL ES フレームワーク。
(4) RealityKit
拡張現実アプリで3Dコンテンツをシミュレートしてレンダリングするために利用されるフレームワーク。Mac での拡張現実アプリは、現実的ではないので、タブレットやスマホのアプリが前提ですね。
(5) RoomPlan
室内をカメラでスキャンして、3Dモデルを作成する際に利用されるフレームワーク。このフレームワークは、主に RealityKit と併用して室内の拡張現実アプリで使われるものと認識しています。
(6) SceneKit
3Dコンテンツ、アニメーション、物理シミュレーション、パーティクルエフェクト(粒子を用いた映像効果)、リアルな物理ベースのレンダリングを組み込んだ3Dゲームを作成するためのフレームワーク。
(7) AGL
macOSで使用する(非推奨となっている)OpenGLレンダリングコンテキストを作成および管理し、描画可能なオブジェクトの操作を実行するフレームワーク。
(8) ARKit
ハードウェアセンシング機能を統合して、拡張現実アプリやゲームを作成するためのフレームワーク。RealityKit 同様、Mac での拡張現実アプリは、現実的ではないので、タブレットやスマホのアプリが前提ですね。
(9) GameplayKit
ゲームロジックを設計し構成、乱数生成、人工知能、パスファインディング(経路探索)、エージェントの行動など、一般的なゲームプレイ行動を取り込むためのフレームワーク。
(10) Metal Performance Shaders
各Metal GPUファミリの特性に合わせて微調整されたカーネルで、グラフィックスと計算性能を最適化するためのフレームワーク。
(11) Metal Performance Shaders Graph
線形代数、機械学習、コンピュータビジョン、およびその他の類似の領域用に、カスタマイズされた多次元コンピューティンググラフを構築、コンパイル、実行するためのフレームワーク。
(12) MetalFX
GPUの時間を節約するために、低解像度のコンテンツをアップスケールすることで、Metalアプリのパフォーマンスを向上させるフレームワーク。
(13) MetalKit
汎用的なユーティリティクラスのセットを使用して、Metalアプリをより迅速かつ簡単に構築するためのフレームワーク。これまで確認してきたフレームワーク。
(14) ShaderGraph
Reality Composer Proで3Dコンテンツのカスタムマテリアルとエフェクトを作成するためのフレームワーク。
(15) Spatial
3次元の数学的要素の生成と操作を行うためのフレームワーク。このフレームワークについても、一度、内容を確認してみたいと思います。
これらの検索結果に「Core Animation」は見当たらず、3Dのカテゴリではないようです。当然ながら、「Animations」をキーワードとした検索では、ヒットします。
そして、このページに詳細については、「Core Animation Programming Guide」 を参照と示されています。
この「Core Animation Programming Guide」は、それなりのボリュームがあり、そうそう確認できそうにありません。また、時間がある時に改めて確認することとし、一旦保留とします。😞
2024年2月12日
せっかく自動で隠面処理される直方体の3D描画が行えたところで、透明度を適用した描画も試してみました。Metal シェーダーへ渡している描画色データには、透明度のフィールドもありましたが、デフォルトでは適用されておらず、RenderPipelineDescriptor にアルファブレンドの設定とやらが必要のようで、その設定コードを追加しています。
残念ながら、元々の描画の配色のセンスの悪さもあって、透明感が分かりずらいイメージになってますね。😣
ようやく、今年最初のテーマである模型飛行機描画のモデル・データを独立クラスにするためのリファクタリングに着手します。
2024年2月13日
シンプルな(直方体のような)要素モデルのクラスをもとに、複数のモデル(例えば二つの直方体)を組み合わせたモデルを生成するクラスを用意し、レンダリングするようにクラス構成を変更しました。
さらに、要素モデルを任意の大きさで、任意の位置にコピーするユーティリティを整備していきたいと思います。
2024年2月14日
モデルを任意の大きさで、任意の位置にコピーするユーティリティを整備し、描画する直方体を増やしていたら、「セットする頂点のバッファサイズが大きすぎる」旨のエラーとなってしまいました。複数のモデルを組み合わせたモデルで一気に描画させようと考えていましたが、バッファサイズに4096バイトの制約があり、小分けして描画するように変更しなければならないようです。😣
2024年2月15日
一回の頂点データの書出しが4096バイトを超えないように分割し、より多くの直方体を描画できるようになりました。
モデルの配置時点で回転が行えるようにユーティリティの整備を進めます。
2024年2月16日
モデルの配置時点で回転を行って直方体を描画してみました。一部の直方体が重なっているところがありますが…😅
2024年2月17日
回転して配置するなら、これぐらい増やしてみましょう。😆
2024年2月18日
描画する直方体の数を増やしてみました。12x12x12 計 1,728 個の描画だとこんな感じです。使用している Mac mini (2018) の CPU が「3 GHz 6コア Intel Core i5」GPU が「Intel UHD Graphics 630 1536MB」で、Xcode 上からの実行で、17 fps (frames per second) まで下がってしまいました。おそらく、最近の Apple Mxチップ の Mac であれば、楽々 60 fps をキープできると思います。
ちなみにワイヤーフレームの場合、44 fps で、深さのテストを設定しなかった場合でも、43 fps でほぼ変わりませんでした。
補足:この実装では、フレーム描画毎にモデルの頂点データを(スライダーの値により)回転させているため、その分のチューニングが行える余地があります。
性能については問題になったら、チューニングを行うことにして、本題に戻り、模型飛行機のモデルデータを Microsoft C# 版から、Swift 版へ移植しました。
Microsoft C# 版から持ってきた模型飛行機のモデルデータは、ワイヤーフレームの描画データしかなく、要素としては、本体(ボディ)部分と、ブレード部分で構成されています。プロペラは、ブレード2枚でなので、180度回転したものを追加しています。
あと、飛行機単体は、なぜか、左向きに描かないと落ち着かないですよね…😖
そうして、ようやく、模型飛行機2機の旋回飛行の3D動画の描画を実装することができました。
引き続き、2023年12月31日に掲げたサンプル画像と同じように、垂直上昇旋回と垂直旋回を加えていきたいと思います。
2024年2月19日
2023年12月31日の掲げたサンプル画像と同じように、垂直上昇旋回と垂直旋回を加えた模型飛行機6機の3D動画の描画が完成しました。
今回、模型飛行単体のモデル・データは、Microsoft C# 版から持ってきたので、見た目をほとんど変えずに3D動画を実装できた訳ですが、変わり映えしないのも、なんとなく寂しい感がしています。
今回、Mac 上での Swift と、Metal フレームワークを使った3D描画では、隠面処理が自動で行えることや、ベクトル演算や、GPU側の並列処理の仕組みが理解できたので、今後は、もう少し高度な、3D描画の実装に挑戦していきたいと思います。
さて、次のテーマを考えましょう!😑
2024年2月20日
次の段階のテーマへ進む前に、Metal を使った 3D 描画で試しておきたいこととして、テキストを混在した描画がありました。
MSL仕様書をキーワード「text△」、「font」で検索してみましたが、残念ながら、ヒットしませんでした。
ネットを検索してみると、どうやら、あらかじめ必要なテキストをイメージ化し、テクスチャとして Metal へ引渡し描画するといった方法で実現しているようでした。
もしくは、三角形の組み合わせで、字形を描画するか。数字とアルファベット程度の文字だけなら、力技で不可能ではなさそう…😔
ちなみに、Windows Microsoft C# 環境での System.Drawing.Bitmap を使ったグラフィックス描画では、Text の書き込みを行うAPI が提供されていただけに、ちょっと残念です。
2024年2月21日
Metal で、テクスチャを用いた文字描画について、調査中。
2024年2月22日
Metal で、テクスチャを用いた文字描画について、あれこれ探していましたが、なかなか見当たらず、とりあえず、次の参考サイトをもとにテクスチャを貼り付ける実装サンプルコードを確認してみます。
2024年2月23日
前出の参考サイトをもとにテキストをイメージ化したテクスチャを三角形2枚に貼り付け描画してみました。
このように単純なテクスチャ描画でも、三角形の各頂点ごとにテクスチャ・イメージのどの部分を貼り付けるか座標の対応付けが必要で、しかも、三角形の描画座標系とテクスチャの座標系が異なるため、初めは困惑してしまいます。(座標系については、2024年2月4日の記録を参照)
2枚の三角形を使って描画していますが、三角形の柄合わせは、まるで、裁縫の柄合わせのようです。説明では、分かりづらいので、柄合わせができていないサンプルも載せておきます。
単純に最前面に文字表示する場合でも、奥行きのある3D描画で文字表示する場合でも、文字以外の部分は、透過したいことがあると思いますが、どのように実現できるのでしょうか。さらに調べてみる必要があります。🙁
このあと、透過PNGでテクスチャ・イメージを作って貼り付けてみたら、文字以外の部分を透過したままで描画することができました。😅
あとは、Swift 側で表示したいテキストを透過イメージ化して、Metal に引き渡すことができれば良いということになります。今回は、前出の参考サイトに倣い 、あらかじめ PNG イメージファイルを Swift プロジェクトの Assets.xcassets に格納して参照していましたが、アプリ側で任意のテキストを表示させるためには、メモリ上で透過イメージを生成させる必要があります。
または、表示させる文字が特定できるのであれば、それらの文字を含む透過 PNG ファイルを Swift プロジェクトの Assets.xcassets に格納しておき、テクスチャとして描画する際に、対象文字を切り出して表示させることができるようです。
次の段階として、直方体と文字テクスチャを混在した3D描画を実装してみたいと思います。
2024年2月24日
ようやく、直方体と(たった一文字の)文字テクスチャを混在した3D描画を実装できました。Metal のシェーダーの実装で、vertex 関数と fragment 関数は、ソリッドの描画とテクスチャの描画とも共用しなければならないので、若干手間取ってしまいました。
次の段階へ進む前に、ソリッドの描画とテクスチャの描画を行う実装について、リファクタリングしておきたいと思います。
2024年2月25日
リファクタリングと併せて、要素モデルにテクスチャの描画データを含められるようにして、複数配置できるようにしてみました。
さて、改めて、次のテーマを考えましょう!😑
これまでの記録を振り返り、3D描画ネタとしてメモしていた内容は、以下の通りでした。
これらの中から、次の段階のテーマは、『ロボットアームを動かしている3D動画の描画』としたいと思います。
私の考え方としては、3D描画は『メモリー上で作成した3Dモデルを画面上の2次元のイメージにすること』ですが、静的な3Dモデルを2次元イメージに描画するだけなら(その芸術的観点は別として)絵を描くことと変わらないので、『動きのある3Dモデルの2次元イメージ化』として(芸術的観点は抜きにした)『ロボットアームを動かしている3D動画の描画』に取り組みたいと思います。
『ロボットアームを動かしている3D動画の描画』のポイントとしては、動きのある要素が複合していることです。ロボットアームの場合で言うところの可動軸が二つ以上ある物体の動きを3D動画として描画することにチャレンジしてみたいと思います。
2024年2月26日
ロボットアームのイメージをスケッチしてみました。何となく、よくありそうなもので、描いてみたら、可動軸が4つになってしまいましたが、先端は何と言うのか分かりませんが、マジックハンドみたいなイメージです。描画する要素としては、7つになりそうです。
イメージをスケッチして、気づいた課題としては、それらの要素のモデルを編集するためのツールが Mac 上に有るのかという事です。
あまり凝ったモデルにするつもりはないので、方眼紙使って頂点を採っていくのも有りかと思いますが…
Windows OS 上で整備したツールを使うのも一つの手段としてありますが、脱マイクロソフト志向で、出来るだけ控えたいと思います。
何か、良い方法がないか、検討してみたいと思います。😖
2024年2月27日
テーマが変わったにも関わらず、一昨日の文字テクスチャを含む3D描画の延長で、漢字の表示を試してみました。アルファベットだろうが、漢字だろうが、イメージファイルからの切り出しで表示しているだけなので、当たり前に表示できるのですが、何となく試しておきたくなりました。😅
ロボットアームを構成する要素のモデルについては、特段見栄えを抜きにして、ざっくりした直方体をベースに、必要に応じ部分的な切り落としを行い作成していきたいと思います。後々に、気が向いたら見栄えも考えていきたいと思います。
2024年2月28日
ロボットアームを構成する要素の一個目は、2月26日のスケッチの①の部分。
頂点の順番などを気にして、並び替えたりしていたら、たったのこれだけ…😞
普段なら Mac 上でも、Excel に頼るところ、慣れない Numbers を使って頂点座標の書き出しをしてみました。
2024年2月29日
ロボットアームを構成する要素の二個目は、2月26日のスケッチの②の部分を追加。直接頂点データをコーディングするのは、地味な作業です。🙁
続きは、次のNote に掲載します。