ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
Metalレイトレーシングのガイド
Metalレイトレーシングでゲームやアプリのビジュアルクオリティを向上させる方法を紹介します。MetaレイトレーシングAPIの基本を確認しましょう。よりスケールが大きく複雑なシーンの作成、メモリ使用量とビルドの時間の削減、髪や毛皮などのビジュアルコンテンツの効率良いレンダリングなどを可能にする、最新の改善点やテクニックについて解説します。
関連する章
- 0:09 - Intro
- 1:50 - Build your scene
- 9:48 - Scale with instancing
- 17:34 - Build with parallelization
- 18:34 - Refitting
- 19:47 - Compaction
- 21:14 - Intersect rays
- 26:16 - Debug and profile
- 30:42 - Wrap-Up
リソース
- Accelerating ray tracing using Metal
- Metal for Accelerating Ray Tracing
- Rendering reflections in real time using ray tracing
関連ビデオ
Tech Talks
WWDC22
WWDC21
WWDC20
-
ダウンロード
♪ ♪
こんにちは Pawel Szczerbukです 私はGPUソフトウェアエンジニアです Metalはレイトレーシングアプリの より複雑で 詳細なシーンを拡張するのに役立ちます レイトレーシングはプロダクションの レンダリングにおける画像の再現度合いが 基本となりますが、 ゲームでは画質の向上に加え 高フレームレートに焦点が当てられます これはMetalレイトレーシングでレンダリングされた ディズニーのモアナ島の画像です 今日はMetalレイトレーシングの 使用方法についてお話しします ゲームとプロダクションレンダラーで レイトレーシングを加速する 新機能に焦点を当てます
レイトレーシングアプリは シーン内を反射する 個々の光線をシミュレートします Metalレイトレーシングでは まずシーンのジオメトリの定義が 第一ステップです 次にMetalはジオメトリを含んだ Acceleration Structureを作成し GPUアクセラレーションで 効率よく交差点を照会します GPU functionで シーンと交差するレイを作成し シェーダーでIntersectorを作成し レイとacceleration structureと共に 供給します こうしてピクセルに影が必要か さらに処理が必要か などの情報とともに intersection resultが戻ります これらが一緒に働いてシーンを作成し インスタンスで視覚的複雑性を加え レイの交差を実行します またレイトレーシングアプリでの 作業に役立つ 数々の素晴らしいツールがあります まずはシーンの構築からです MetalレイトレーシングAPIは いくつかのジオメトリタイプに対応します これらのジオメトリは acceleration structureに保存されています
Acceleration structureは ジオメトリを再帰的に分割して レイトレーシング過程を スピードアップします これによりレイと交差しないジオメトリを 素早く削除することができます Acceleration structureの セットアップには3ステップあります Acceleration structure descriptorで 実際のジオメトリを供給します Descriptorができれば Acceleration structureを割り当てし ビルドします Acceleration structure descriptorには 1つ以上のジオメトリdescriptorがあります Metalには3タイプのdescriptorがあります トライアングルは周知のプリミティブであり コンピュータグラフィックの ほぼすべてに使用されます バウンディングボックス・プリミティブは レイがバウンディングボックスに 当たる時にMetalが呼び出す カスタム交差機能により定義されます 今年はカーブが加わります 髪や毛皮のレンダリングに最適です トライアングルを使って acceleration structureを作るには 個々のジオメトリにトライアングル ジオメトリdescriptorを作ります Vertex bufferとindex buffer そしてtriangle countを供給します バウンディングボックス・ジオメトリも よく似ていますが verticesの代わりに ジオメトリを取り囲む バウンディングボックスを供給します 更にレイがバウンディングボックスに 当たる時に Metalが呼び出す intersection functionを供給します
Intersection functionの セットアップについては WWDC20のDiscover ray tracing with Metalをご覧ください
髪や毛皮や草木などのジオメトリには 何百万にも及ぶプリミティブが あるかもしれません これらは通常細いスムーズなカーブを かたどっています トライアングルで このカーブに近づける代わりに Metalの新しいカーブ・プリミティブを 使用できます これらのカーブはカメラがズームしても スムーズさを保ちます トライアングルと比べて カーブのメモリ・フットプリントは小さく より速いacceleration structure buildsが可能です
カーブはいくつもつながった 曲線分から成り立っています その一分一分がプリミティブで Metalは各曲線分にユニークな プリミティブIDを割り当てます 各曲線分はカーブの形を制御する いくつもの制御点で定義されています これらの制御点は基底関数のセットで 補間されています 基底関数によって 各曲線分には2・3・4か所の 制御点があります Metalは4つのカーブ基底関数を提供します ベジェ キャットムル-ロム B-スプライン リニアです 各基底関数にそれぞれの利点がありますので 最適のものをお選びください Metalはまた制御点の index bufferが必要です 各曲線分にindex bufferが一つあり 曲線分の最初の制御点を示します 例えば制御点が4つあるとします 最初の制御点のインデックスを使って 曲線分を定義するため index bufferに0を加えます この例ではキャットムル-ロム基底関数を 使用しており 実際の曲線分は 制御点1と2の間に定義されます 別の曲線分をつなぐには 制御点をもう1つ加えるだけです この曲線分は制御点1から4を使用するため index bufferに1を足します Index bufferのために 2つの曲線分が3つの制御点を共有するため カーブはメモリの使用を抑制できます カーブが完成するまでこれを繰り返します 新しいカーブを始めるには それまでの制御点に交わらず さらなる制御点を足せばいいだけで index bufferに 対応するインデックスを足します 今のところこのカーブは 抽象な数学的なオブジェクトです これらをレンダリングするには 何らかの3次元形状が必要です 各制御点には半径があり カーブの長さ中を補間しています 既定としてカーブは 3次元円筒形の横断面と共にレンダリングされます クローズアップになるカーブには最適です 遠くからしか見られないカーブの場合 Metalはフラットカーブもサポートします 3次元ジオメトリが必要でない時の パフォーマンスが向上します
トライアングルなどと同様に カーブジオメトリは curve geometry descriptorで定義されます controlPointBufferと 対応するradiusBuffer及び indexBufferを取り付けます 制御点バッファの制御点の数と 曲線分の実際の数をセットします Index bufferの インデックス数と同じはずです カーブのタイプを指定します この例では各曲線分に4つの制御点を持つ ラウンドベジェカーブです Curve geometry descriptorの 設定に必要なのはそれだけです
ジオメトリdescriptorを作ったところで acceleration structure descriptorを セットアップできます トライアングルなどの プリミティブジオメトリに PrimiticAcceleration StructureDescriptorを使います AccelerationStructureDescriptorに geometryDecriptorを足します ジオメトリを結合するため 1つのAccelerationStructureに いくつものgeometryDesciptorを 足せます Acceleration structure descriptorが 用意できれば acceleration structureに メモリを割り当てできます Metalでその時と場所を完全制御できます
これは二部構成の作業です まずビルドに必要な オブジェクトのサイズを計算します MetalデバイスはAcceleration structureに 必要なアロケーションサイズを 計算するメソッドを提供します Metalデバイスから直接ストレージを 割り当てすることができますが Heapからすることで 後にリソース管理のオーバーヘッドを 減らすことができます それには更なるサイズや配置条件を 要するかもしれませんが Metalデバイスの別のメソッドで 照会できます このサイズならacceleration structureを 保管するメモリを割り当てできます このストレージは MTLAccelerationStructureで示されます これらを割り当てするには HeapかMetalデバイスでサイズをパスし makeAccelerationStructureメソッドを 呼び出します またMetalがacceleration structureを 作る間に使うスクラッチメモリも 割り当てします このメモリへのアクセスは GPUだけでいいため Metalデバイスからprivate storage mode bufferを割り当てするだけです
これでacceleration structureを ビルドする準備ができました ビルドをスケジュールすれば MetalがGPUでaccelerationをビルドします Acceleration Structure Command Encoderを使用します
このエンコーダには acceleration structureを作成し 改良するためのメソッドが 幾つかあります この場合 destination acceleration structureとdescriptor 及びscratch bufferで buildメソッドを呼びます Metalがジオメトリの primitive acceleration structureを作成し 後のGPU commandsで使用可能になります このようにして primitive acceleration structureで シーンにジオメトリを描写できます 大きいシーンのスケーリングに Metalはinstance acceleration structures をサポートしています 1つのprimitive acceleration structureでは モアナ島のような複雑で詳細な環境の保管に 莫大なメモリが必要になります しかしこの複雑なシーンには 何千の木々や 何百万もの葉やそれ以外の 繰り返し構造物があり シーンを効率よく レンダリングすることができます 山やサンゴや木々など シーンのユニークな物すべては primitive acceleration structuresとして 描写できます これらをinstance acceleration structureにまとめて シーン全体を描写できます つまりprimitive acceleration structureがジオメトリを含むのに対し instance acceleration structureには シーン全体の構成のため 位置やサイズや向きが変えられた ほかのacceleration structuresへの参照が 含まれています 各インスタンスにシーンで参照される acceleration structureを配列する 変換行列があります Instance acceleration structureの作成は primitive acceleration structureの 作成と似ています まずdescriptorの作成から始まります この場合はジオメトリの代わりに 参照されたacceleration structureや シーンに配置される transformation matrixなど 各インスタンスの情報を含む バッファを供給します そしてprimitive acceleration structureと同様に GPUでacceleration structureを ビルドします
Descriptorの作成にはMTL Instance Acceleration Structure Descriptorを築き 含まれるインスタンスの数をセットします そしてインスタンスに参照される primitive acceleration structuresの 配列を供給し instance bufferに含まれる instance descriptorのtypeを特定します ユースケースによって選べる instance descriptor typesを Metalは提供します acceleration structureでの インスタンスの設定は2ステップです
まずper-instance dataを 保管するバッファを割り当てします このバッファのサイズはインスタンスの数と instance descriptorのサイズ次第ですが ほかのMetalバッファ同様に 割り当てできます バッファーを割り当てたら それをinstance acceleration structure descriptorに割り当てます
次にacceleration structureにある すべてのinstanceの情報を instance bufferに詰め込みます Instance毎にdescriptorを作り このinstanceが参照する acceleration structureを特定します Instance acceleration structure descriptorでセットした acceleration structure index配列を 確認します また使用する instance descriptorのtypeによって 各instanceには transformation matrixや visibility maskなどの プロパティがあります
最後のステップは acceleration structureのビルドで primitive acceleration structureと 同じプロセスです ビルドまでのステップはすべて CPUで実行可能です しかしinstancesの数が大きいと instance bufferの書き込み処理に 多大な負荷がかかります Instance descriptorsは 通常のMetal bufferに格納されているため GPUからdescriptorsを書き込むことで このステップを加速できます GPUに作業を手渡す前に acceleration structureにinstancesが 幾つあるかわかっている限り これはGPUアクセラレーションの いい機会です しかしinstance cullingなどを 行いたい場合は descriptorで 最終Instance countができるよう CPUでinstancesをcullしなければいけません 今年から新しいindirect instance acceleration structure descriptorで この処理がGPUで可能になりました このindirect descriptorで instancesのcullや instance bufferの書き込みや 最終instance countのセットが すべてGPUで行えます GPUによる acceleration structureビルドを行うには indirect instance acceleration structure descriptorを作成します descriptorの maximum instance countと GPUからの最終instance countを書く bufferをセットします そしてinstance descriptor bufferをセットし GPUでのinstancesの設定が可能になります
Instance bufferで 違ったdescriptor typeを使用します Indirect instance descriptorは direct instance descriptorに似ていますが descriptorに単に割り当てるだけで acceleration structureが 例証されているか確認できます こうしてinstance acceleration structureを作成します これまで2レベルモデルの インスタンスに触れてきました このモデルではモアナ島シーンの森林が 何千もの種類の木々のインスタンスで 構成されています しかし掘り下げて見ると 木は葉のコピーを幹に取り付けたものです この構造の場合 新機能である マルチレベルインスタンスを 利用することができます マルチレベルインスタンスで instance acceleration structureは primitive acceleration structuresだけでなく ほかのinstance acceleration structuresも含めます このシーンの例ではシーン全体としては ヤシの木のインスタンスを含む一方 ヤシの木は幹と葉のインスタンスを含む instance acceleration structure として表現できます モアナ島はマルチレベルインスタンスの パワーを示す非常にいい例です 2レベルインスタンスの場合 シーンに1つのタイプの木を足すのは 何百または何千もの木のパーツのコピーを 足すということです マルチレベルインスタンスでは パーツの繰り返しインスタンスで定義された 複雑な木のインスタンスを 足せるということです つまりモアナ島シーンで 何百万ものインスタンスを省けるのです しかしマルチレベルインスタンスは プロダクションのためだけではありません ゲームのような リアルタイムアプリでも貴重です 2レベルacceleration structure patternは ゲームオブジェクトのインスタンスから 世界を作り出すなど ゲーム制作でも使用されています しかしゲームは プロダクションレンダラーとは違います プロダクションはオブジェクトの再利用に 深い階層を使用しますが ゲームはゲームオブジェクトインスタンスの 長いリストを使用します またゲームは動的コンテンツのために instance acceleration structureを フレーム毎に再建するため インスタンスの数が多いと GPUの処理時間が増加します
しかしゲームでは多くのコンテンツが静的で フレームの更新は必要ありません acceleration structureの更新を 変化があるコンテンツだけに限定するため acceleration structuresを 静的と動的に分けることができます つまり動的コンテンツだけを処理するため 通常 静的コンテンツより少なく済みます 静的と動的コンテンツに分ける時 ray traversalコストを追加して 階層の深さの バランスをとることが重要です Acceleration structureのビルドと レイトレーシングのあるフレームでは 3レベルのインスタンスの使用で トレーシングに最小限の影響だけで ビルドの時間を削減できるため フレーム全体での時間が削減できます マルチレベルインスタンスは メモリ使用量を減少させ リビルドの時間短縮に最適です またMetalレイトレーシングアプリを 最適化できる方法があります その一つがBuild parallelizationです
通常アプリは違うシーンや そのパーツを描写する 多くのacceleration structuresを ビルド及び更新する必要があります これらのビルドを並行に行うことで 起動時間を減少できます
可能であれば並行に実行できるよう 複数のビルドを同じ command encoderにエンコードし ビルドをバッチするようにします メモリ容量を超えないよう確認しながら できるだけ多くのビルドを 並列化するようにしましょう またacceleration structureの ビルドが終了すると scratch bufferは不要になります つまりscratch buffersを 一束のacceleration structureビルドから 次のものに使用できるのです Acceleration structureのリビルドの時間を 削減するのにリビルドを避けることが 最善策であることもあります Acceleration structure refittingが 役に立ちます Metalがacceleration structureを作る時 近辺のプリミティブを箱の階層に グループ分けします もしプリミティブが動くと これらの箱はシーンを正確に描写できず acceleration structureは 更新されねばなりません でもジオメトリの変化が少しだけなら この階層はまだ道理が合うかもしれません 新しいacceleration structureを 一から作り直す代わりに Metalはプリミティブの 新しい位置を反映するため 既存のacceleration structureを リフィットできます Acceleration structureを 一から作り直すより簡単です Refitはbuild operationのような scratch bufferが必要です Refit scratch bufferのサイズは 先ほどacceleration structureを アロケートするのに使った 同じ構造体にあります RefitはGPUで実行され acceleration structure command encoderでエンコードされます Refitは所定の場所か別の acceleration structureで実行できます
最後にcompactionはメモリにおける acceleration structuresの サイズの減少に最適です 最初にacceleration structureを作る時 Metalはどれだけメモリが必要かわからず 控えめな見積もりを出さねばなりません いざacceleration structure作ったら Metalはそれを描写するための 必要最小限のサイズを計算します Compactionは必要最小限サイズの acceleration structureを アロケートし GPUを使って 現在のacceleration structureから 新しいものにコピーします これは特にprimitive acceleration structuresに役立ちます Compactionを使うにはGPUにある acceleration structureのcompacted sizeを 計算するコマンドをエンコードします このコマンドを実行すると Metalはcompacted sizeを 供給されたbufferに書き込みます いざcompacted sizeを読めば そのサイズの新しい acceleration structureをアロケートし 古いものから 新しいacceleration structureに copy and compact処理をエンコードします このcommand bufferが完了すれば 元のacceleration structureを リリースできます Metalレイトレーシングアプリの 最適化については WWDC22のMaximizing your Metal ray tracing performanceをご覧ください このセクションでは インスタンスのセットアップと マルチレベルインスタンス機能の利用と インスタンスのスケールについて話しました ではレイをシーンに交差させる時です Metalではコマンドの一部として実行する GPU Functionでレイを交差します Apple Siliconではcomputeと renderコマンドの両方でレイを交差でき AMDとIntelでは computeコマンドでレイを交差できます レイを交差させるために command encoderで acceleration structureをバインドします これでGPU Functionで このacceleration structureとレイを 交差できます acceleration structure parameterで functionを宣言し intersector objectを作成します 最高のパフォーマンスでの レイ交差の設定のため このintersectorに プロパティをセットできます レイをシーンと交差させるため レイを作成し intersector objectに intersect methodを呼び出し レイとacceleration structureを パラメータとしてパスします これによりintersectionの 情報すべてが返ってきます レイが交差するプリミティブの種類や intersectionの距離や プリミティブのIDなどです
Triangle intersection pointの 情報が知りたいなら triangle dataタグをintersectorと intersection result typesに足します これにより triangle barycentric coordinatesが intersection resultで得られます Primitive acceleration structureとの レイの交差については以上です Instance acceleration structureと レイの交差もよく似ています Primitive acceleration structureの バインド同様に instance acceleration structureを バインドします GPUのinstance acceleration structureで acceleration structuresが参照されるよう useResourceかuseHeapを 必ずコールしてください レイとinstance acceleration structureを 交差させるにはGPU functionに 少し変更を与えるだけです まずacceleration structure typeに instancingタグを足します そしてintersectorと intersection resultに instancingとmax levelsタグを付けます Max levelsタグは acceleration structureでの インスタンスレベルの数を指定します 例えばモアナ島シーンを描写する acceleration structureは 3レベルacceleration structureです 最初のレベルはシーン全体を含んだ instance acceleration structureです 2つ目のレベルにはサンゴや木々 そして地形のインスタンスがあります 3つ目のレベルは葉や花や幹など 木のパーツのインスタンスです レイがシーンと交差する時は プリミティブと交差するだけでなく プリミティブを含む インスタンスとも交差します もしレイがこの木の葉と交差したら 木のインスタンスや木にある葉の インスタンスとも交差するのです Metalは交差したインスタンス 一つ一つのIDを記録して これを監視しています この場合 最初に交差したインスタンスは 6のIDを持つ木で 2つ目に交差したインスタンスは 1のIDを持つ葉です 交差するインスタンスが 一つの時もあります 例えばレイが地形と交差したら Metalは地形インスタンスのIDしか 記録しません Intersection resultで 交差したインスタンスの数とIDを 見つけることができます Primitive acceleration structuresと instance acceleration structuresに こうしてレイを交差できます カーブプリミティブの場合 注意すべきことが幾つかあります 既定ではレイの交差を実行する時 Metalはカーブプリミティブを 使用していないと仮定しています Metalにカーブの使用を伝えるには intersector objectで geometry typeを設定します Geometry typeを設定すれば カーブに交差できます 以前と同様 intersection resultで intersectionの情報を得られます もしcurve dataタグを使えば intersection resultも curve parameterを含みます これはカーブがレイと交差する点を算出する カーブの基底関数に挿入される値です これらの関数はMetal Shading Languageに 実装されています 詳細はMetal Shading Language仕様書を ご覧ください 多くのアプリでカーブジオメトリは 一種のカーブだけで描写されています 例えば シーンのカーブすべてが 円形横断面の3次ベジェ曲線と 表現されているかもしれません この場合 intersector objectで カーブのプロパティを設定して どのようなカーブが使用されているか Metalに指定できます カーブプリミティブを使用する際 これで最高の性能が得られます このようにしてレイを交差させます レイトレーシングの作業負荷はXcodeで デバッグ及びプロファイルできます
デバッグにおける困難な問題には Shader Validationを 使用できます シェーダーのランタイムチェックを行い クラッシュや破損に つながる問題を発見します Shader Validationは 最新のレイトレーシング機能を含む すべてのMetal APIをカバーします さらにShader Validationにより シェーダーコンパイルの時間が削減されます これはレイトレーシングアプリに よく見られる 長く複雑なシェーダーの使用時に便利です また役に立つもう一つのツールは最新式の Acceleration Structure viewerです 交差テストに使用するシーンの検査を 可能にします Acceleration Structure viewerを開けると ジオメトリプリミティブに及ぶまでの acceleration structureにおける ビルディングブロックの概要が 左側に表示されます トライアングルジオメトリを構成する 各トライアングルがここに表示されています 右側のビューポートでは 数々のハイライトモードにおける acceleration structureを点検できます 例えばAxis-Aligned Bounding Box Traversalsハイライトモードでは 負荷がより大きい intersection testingに該当する トラバーサルの深いエリアを 視覚化することができます ポインタを動かすと そのポイントで示された方向において レイが交差する数をinspectorが更新します 別の例がAcceleration Structure ハイライトモードです Acceleration structuresを 違う色で視覚化できます Acceleration Structure viewerは 新機能のマルチレベルインスタンスと カーブジオメトリをサポートします ビューポートでカメラを動かすと 木々のinstance acceleration structuresや 葉のカーブを見つけることができます Acceleration structureの確認には ビューポートでクリックすると アウトラインが現れます このヤシの木の葉の acceleration structureを 詳しく見てみましょう このacceleration structureでは 葉はカーブで構成されています プリミティブハイライトモードに変えると 曲線分を視覚化できます 曲線分をさらに視察するため 少し拡大してみます 先程シーンで acceleration structuresを選んだように 各曲線分をクリックして選択できます レイトレーシング作業量の検査に便利な もう一つのツールが Shader Debuggerです シェーダーコードでの問題解決に役立ちます これはシェーダーで intersection testingを行う compute dispatchです シェーダーのデバッグを始めるには Shader Debuggingボタンをクリックし ポップオーバーでスレッドを選び Debugボタンをクリックします
データの収集後 シェーダー実行中どの時点でも 変数値を確認することができます プリミティブIDの値を見てみましょう さらなるデバッグコンテキストに Shader Debuggerは 近辺のスレッドからのデータを示します ポインタをvalueビューにかざすと 同じスレッドグループからの プリミティブIDを確認できます
どのアプリにおいても その性能はもう一つの重要な要素です Profiling timelineは レイトレーシング作業性能の概要を示し あらゆる性能メトリックを並べて確認 及び関係付けることが可能になります さらにDebug navigatorを すべての作業量のpipeline statesに 変えることも出来ます またshader profiling dataで 最も負荷量の大きいpipeline statesを 上からリストすることも出来ます さらにpipeline stateを拡張すると shader codeが表示されます シェーダーを開いたあと 各シェーダーがどこでどう 実行時間を費やすか行毎の shader profiling insightsが得られます サイドバーの円グラフにポインタをかざすと コードのその行での作業負荷の詳細が ポップオーバーに表示されます これらのツールはMetalレイトレーシングの 新機能をすべてサポートし Metalアプリ作成の デバッグやプロファイルの 素晴らしい手助けとなります
またMetalレイトレーシングは さらなる機能をサポートします プロダクションレンダラーでの動画での primitive及びinstance motionや alpha testingなどの改善を含む ray intersectionの カスタム化のための custom intersection functions そしてクエリベースAPIからの 移植性のためのintersection queryなどです MetalレイトレーシングAPIや 言語及びツールは ゲームやプロダクションレンダラーなど リアルタイムレンダリングアプリに対応します 最新MetalレイトレーシングAPIで カーブのようなジオメトリを含む primitive acceleration structuresを 使ってシーンを構築できます インスタンス 特に新しい マルチレベルインスタンス機能で さらに大きく複雑なシーンに スケールできます MetalレイトレーシングAPIは GPU functionsで直接呼び出せます 最後にアプリのデバッグとプロファイルに Xcodeが役に立ちます これらのトピックの詳細をカバーし サンプルコードや書類にアクセスできる 以前のセッションもぜひご視聴ください ありがとうございました ♪ ♪
-
-
3:06 - Create triangle geometry descriptor
// Create geometry descriptor: let geometryDescriptor = MTLAccelerationStructureTriangleGeometryDescriptor() geometryDescriptor.vertexBuffer = vertexBuffer geometryDescriptor.indexBuffer = indexBuffer geometryDescriptor.triangleCount = triangleCount
-
3:20 - Create bounding box geometry descriptor
// Create geometry descriptor: let geometryDescriptor = MTLAccelerationStructureBoundingBoxGeometryDescriptor() geometryDescriptor.boundingBoxBuffer = boundingBoxBuffer geometryDescriptor.boundingBoxCount = boundingBoxCount
-
6:42 - Create curve geometry descriptor
let geometryDescriptor = MTLAccelerationStructureCurveGeometryDescriptor() geometryDescriptor.controlPointBuffer = controlPointBuffer geometryDescriptor.radiusBuffer = radiusBuffer geometryDescriptor.indexBuffer = indexBuffer geometryDescriptor.controlPointCount = controlPointCount geometryDescriptor.segmentCount = segmentCount geometryDescriptor.curveType = .round geometryDescriptor.curveBasis = .bezier geometryDescriptor.segmentControlPointCount = 4
-
7:29 - Create primitive acceleration structure descriptor
// Create acceleration structure descriptor let accelerationStructureDescriptor = MTLPrimitiveAccelerationStructureDescriptor() // Add geometry descriptor to acceleration structure descriptor accelerationStructureDescriptor.geometryDescriptors = [ geometryDescriptor ]
-
8:08 - Query for acceleration size and alignment requirements
// Query for acceleration structure sizes let sizes: MTLAccelerationStructureSizes sizes = device.accelerationStructureSizes(descriptor: accelerationStructureDescriptor) // Query for size and alignment requirement in a heap let heapSize: MTLSizeAndAlign heapSize = device.heapAccelerationStructureSizeAndAlign(size: sizes.accelerationStructureSize)
-
8:39 - Allocate acceleration structure and scratch buffer
// Allocate acceleration structure from heap var accelerationStructure: MTLAccelerationStructure! accelerationStructure = heap.makeAccelerationStructure(size: heapSize.size) // Allocate scratch buffer let scratchBuffer = device.makeBuffer(length: sizes.buildScratchBufferSize, options: .storageModePrivate)!
-
8:40 - Encode the acceleration structure build
let commandEncoder = commandBuffer.makeAccelerationStructureCommandEncoder()! commandEncoder.build(accelerationStructure: accelerationStructure, descriptor: accelerationStructureDescriptor, scratchBuffer: scratchBuffer, scratchBufferOffset: 0) commandEncoder.endEncoding()
-
11:30 - Create instance acceleration structure descriptor
var instanceASDesc = MTLInstanceAccelerationStructureDescriptor() instanceASDesc.instanceCount = ... instanceASDesc.instancedAccelerationStructures = [ mountainAS, treeAS, ... ] instanceASDesc.instanceDescriptorType = .userID
-
12:07 - Allocate the instance descriptor buffer
let size = MemoryLayout<MTLAccelerationStructureUserIDInstanceDescriptor>.stride let instanceDescriptorBufferSize = size * instanceASDesc.instanceCount let instanceDescriptorBuffer = device.makeBuffer(length: instanceDescriptorBufferSize, options: .storageModeShared)! instanceASDesc.instanceDescriptorBuffer = instanceDescriptorBuffer
-
12:33 - Populate instance descriptors
var instanceDesc = MTLAccelerationStructureUserIDInstanceDescriptor() instanceDesc.accelerationStructureIndex = 0 // index into instancedAccelerationStructures instanceDesc.transformationMatrix = ... instanceDesc.mask = 0xFFFFFFFF
-
14:06 - Configure indirect instance acceleration structure descriptor
var instanceASDesc = MTLIndirectInstanceAccelerationStructureDescriptor() instanceASDesc.instanceDescriptorType = .indirect instanceASDesc.maxInstanceCount = ... instanceASDesc.instanceCountBuffer = ... instanceASDesc.instanceDescriptorBuffer = ...
-
14:29 - Populate indirect instance descriptor
device MTLIndirectAccelerationStructureInstanceDescriptor *instance_buffer = ...; // ... acceleration_structure<> as = ...; instance_buffer[i].accelerationStructureID = as; instance_buffer[i].transformationMatrix[0] = ...; instance_buffer[i].transformationMatrix[1] = ...; instance_buffer[i].transformationMatrix[2] = ...; instance_buffer[i].transformationMatrix[3] = ...; instance_buffer[i].mask = 0xFFFFFFFF;
-
19:22 - Update geometry using refitting
// Allocate scratch buffer let scratchBuffer = device.makeBuffer(length: sizes.refitScratchBufferSize, options: .storageModePrivate)! // Create command buffer/encoder ... // Refit acceleration structure commandEncoder.refit(sourceAccelerationStructure: accelerationStructure, descriptor: asDescriptor, destinationAccelerationStructure: accelerationStructure, scratchBuffer: scratchBuffer, scratchBufferOffset: 0)
-
20:24 - Use compaction to reclaim memory
// Use compaction to reclaim memory // Create command buffer/encoder ... sizeCommandEncoder.writeCompactedSize(accelerationStructure: accelerationStructure, buffer: sizeBuffer, offset: 0, sizeDataType: .ulong) // endEncoding(), commit command buffer and wait until completed ... // Allocate new acceleration structure using UInt64 from sizeBuffer ... compactCommandEncoder.copyAndCompact(sourceAccelerationStructure: accelerationStructure, destinationAccelerationStructure: compactedAccelerationStructure)
-
21:36 - Set acceleration structure on the command encoder
encoder.setAccelerationStructure(primitiveAccelerationStructure, bufferIndex:0)
-
21:48 - Intersect rays with primitive acceleration structure
// Intersect rays with a primitive acceleration structure [[kernel]] void trace_rays(acceleration_structure<> as, /* ... */) { intersector<> i; ray r(origin, direction); intersection_result<> result = i.intersect(r, as); if (result.type == intersection_type::triangle) { float distance = result.distance; // shade triangle... } }
-
22:24 - Use triangle_data tag to get triangle barycentric coordinates
// Intersect rays with a primitive acceleration structure [[kernel]] void trace_rays(acceleration_structure<> as, /* ... */) { intersector<triangle_data> i; ray r(origin, direction); intersection_result<triangle_data> result = i.intersect(r, as); if (result.type == intersection_type::triangle) { float distance = result.distance; float2 coords = result.triangle_barycentric_coord; // shade triangle... } }
-
22:51 - Set instance acceleration structure on the command encoder
encoder.setAccelerationStructure(instanceAccelerationStructure, bufferIndex:0) encoder.useHeap(accelerationStructureHeap);
-
23:07 - Intersect rays with instance acceleration structure
// Intersect rays with an instance acceleration structure [[kernel]] void trace_rays(acceleration_structure<instancing> as, /* ... */) { intersector<instancing, max_levels<3>> i; ray r(origin, direction); intersection_result<instancing, max_levels<3>> result = i.intersect(r, as); if (result.type == intersection_type::triangle) { float distance = result.distance; // shade triangle... } }
-
24:43 - Find intersected instance information in the intersection result
// Intersect rays with an instance acceleration structure [[kernel]] void trace_rays(acceleration_structure<instancing> as, /* ... */) { intersector<instancing, max_levels<3>> i; ray r(origin, direction); intersection_result<instancing, max_levels<3>> result = i.intersect(r, as); if (result.type == intersection_type::triangle) { float distance = result.distance; for (uint i = 0; i < result.instance_count; ++i) { uint id = result.instance_id[i]; // ... } // shade triangle... } }
-
25:02 - Intersect rays with curve primitives
// Intersect rays with curve primitives [[kernel]] void trace_rays(acceleration_structure<> as, /* ... */) { intersector<> i; i.assume_geometry_type(geometry_type::curve | geometry_type::triangle); ray r(origin, direction); intersection_result<> result = i.intersect(r, as); if (result.type == intersection_type::curve) { float distance = result.distance; // shade curve... } }
-
25:26 - Find curve parameter in the intersection result
// Intersect rays with curve primitives [[kernel]] void trace_rays(acceleration_structure<> as, /* ... */) { intersector<curve_data> i; i.assume_geometry_type(geometry_type::curve | geometry_type::triangle); ray r(origin, direction); intersection_result<curve_data> result = i.intersect(r, as); if (result.type == intersection_type::curve) { float distance = result.distance; float param = result.curve_parameter; // shade curve... } }
-
26:04 - Set geometry type on the intersector for better performance
// Intersect rays with curve primitives [[kernel]] void trace_rays(acceleration_structure<> as, /* ... */) { intersector<curve_data> i; i.assume_geometry_type(geometry_type::curve | geometry_type::triangle); i.assume_curve_type(curve_type::round); i.assume_curve_basis(curve_basis::bezier); i.assume_curve_control_point_count(3); ray r(origin, direction); intersection_result<curve_data> result = i.intersect(r, as); if (result.type == intersection_type::curve) { float distance = result.distance; float param = result.curve_parameter; // shade curve... } }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。