チャレンジ:バインドレスレイトレーシング
2022年6月9日
鏡の中の…もうひとつの鏡。この課題では、Metal 3でのバインドレスレンダリングと鏡面への光線反射について見ていきます。
Metal 3で強化されたバインドレス機能により、HybridRenderingのサンプルAppはこれまで以上に見栄えが良くなっています。Argument Bufferを使用してすべてのシーンリソースをシェーダーで利用できるようにし、Metalのレイトレーシングを使用して、以下のような金属表面の反射を生成します。
Appがこのシーンを美しく描く一方で、まだ限界があります。鏡の床面が鏡の球体を映し出すように、反射の中に反射を表示させることができないのです。
公平な観点:鏡の中に鏡を映し出すのは困難なことです。光が2つの表面間を無限に跳ね返り、計算では解決できない状況を作り出しているのです。レイトレーシングのAppはこの問題を回避するため、シーン内に限られた数の光(レイ)の「バウンド」を追加して、よりリアルな表現ができるようにしています。
この課題では、そのレイトレーシングのコードを拡張し、1つ(またはそれ以上)のレイバウンドを追加することで、イメージのリアルさを向上させています。
課題を始める
この鏡の回廊に入る前に、「Go bindless with Metal 3」をご覧ください。確認後、「Rendering reflections in real time using ray tracing」のサンプルコードをダウンロードしてください。この課題では本コードを使用します。
Metal 3でバインドレスにする
Watch nowRendering reflections in real time using ray tracing
このAppには、画像内の各ピクセルの位置と法線を含む薄いGバッファから反射を計算する専用の計算パスが用意されています。
レイトレーシングのシェーダーがこのデータを読み取り、カメラの向きと合わせて反射光線の方向を計算します。次に、Metalを使ってこれらの光線をトレースし、交差点を見つけ、反射をシェーディングします。
raytracing::ray r;
r.origin = positions.read(tid).xyz;
r.direction = normalize(directions.read(tid).xyz);
r.min_distance = 0.1;
r.max_distance = FLT_MAX;
raytracing::intersector<raytracing::instancing, raytracing::triangle_data> inter;
inter.assume_geometry_type( raytracing::geometry_type::triangle );
auto intersection = inter.intersect( r, accelerationStructure, 0xFF );
if ( intersection.type == raytracing::intersection_type::triangle )
{
// Calculate direct reflections
}
これにより、以下のような画像が生成されます。
しかし、問題があります!床に映る球体から消防車が消えています。レイトレーシングのシェーダー、rtReflection
、 を修正してレイトレーシングのステップを追加し、消えた消防車を映し出すことに挑戦しましょう。
この課題をクリアするためには次のようにします。
- 反射した法線と交差する位置を用いて、次の光線の跳ね返りを計算します。
- マテリアルシェーディングロジックをヘルパー関数に抽出し、反射の中の反射をシェーディングできるようにします。
- すべての反射色を組み合わせ、それを
outImage
に書き込みます。
完成したら、スクリーンショットツール、GPU Debugger、QuickTimeを使ってソリューションをキャプチャし、ハッシュタグ「#WWDC22Challenges」を付けてTwitterに投稿し、みなさんの作品をシェアしてください。また、バインドレスレイトレーシングやその他のグラフィックス&ゲームに関するトピックを議論したい場合は、WWDC22の残りの週を通して開催されるイベントに参加してください。