前回オリジナルLLVMバックエンドを使ってレイトレーシングのプログラムをコンパイルして動かしたのだが、実は「レイトレーシングとは何なのか」良く知らない。コンピュータグラフィックスの授業などは殆ど取ったことが無く、これまでの経験でも使用することが無かったため良く分からない。そこで資料を読んで勉強してみることにした。
- Introduction to Ray Tracing: a Simple Method for Creating 3D Images
https://www.scratchapixel.com/lessons/3d-basic-rendering/introduction-to-ray-tracing
参考にしたのはまさにレイトレーシングのプログラムを拝借してきたサイトから。レイトレーシングのアルゴリズムを丁寧に解説してある。これを読んでみよう。 結構長いのでしっかりGoogle Translateに活躍してもらった。Google Translateの結果を読みながら、要点をつまみ出していく。
また、画像も分かりやすいので本文中から引用させて頂いた。
Implementing the Raytracing Algorithm Adding Reflection and Refraction
今回は Implementing the Raytracing Algorithm と Adding Reflection and Refraction の2節の要点をまとめた。
レイトレーシングアルゴリズムの実装
レイトレーシングのアルゴリズムは、我々の周りで起こっているアルゴリズムに基づいており、ほぼ完ぺきな自然シミュレータとなっている。
画像の各ピクセルについて、目の中心から主光線を発射する。主光線を発射すると、シーン内のすべての物体をチェックして、その物体と交差するかを確認する。場合によっては1時光線が複数の物体と交差するが、その場合には交差点が最も目に近いオブジェクトを選択する。
次に、物体との交点から光源に対して影光線を発射する。この影光線がライトに向かう途中で物体と交差しなければ、好転は光源により照らされていることになる。別の物体と交差する場合、そのオブジェクトには影が発生する。
これをすべてのピクセルに対して実行することにより、3次元シーンの2次元表現が得られる。
サンプルプログラムの掲載はここでは省略するが、レイトレーシングアルゴリズムは非常に短い行数で実装することができ、大体200行くらいで書くことができる。
この方式の欠点はレンダリングに必要な速度である。通常のワイヤフレーム描画の数千倍の計算時間を必要とする。
反射と屈折を追加する
レイトレーシングのもう一つの利点は、光線の伝搬の概念を拡張することで反射や屈折などの効果を非常に簡単にシミュレーションできることである。反射と屈折を再現するためにはどのような要素が必要なのかを考える。
これを説明するために、屈折特性と反射特性の両方を備えた物体であるガラス玉の例を取り上げる。ガラス玉と交差する光線の方向が分かっている限り、計算は簡単である。好転の法線と入射光線(主光線)の方向に基づいている。さらに屈折方向を計算するために屈折率を使用する。光線は基本的に直進するが、別の物質にぶつかると、その方向が変化する。
ガラス玉のような物体は反射性と屈折性があり、これをどのように計算してどのように混合すればよいのか?反射の結果と屈折の結果を半分ずつ持ってきても正しい計算結果でとはならない。主光線(または視線方向)tt物体の法線の屈折率の両方に依存する。これを正確に計算するためにフレネルの方程式というものが知られている。
具体的なステップを考える。まずはシーン内の物体に対して、視点から光線を発射する。光線が拡散する物体、もしくは不透明でない物体に当たった場合には追加の計算作業を行う必要がある。例えば、ガラス玉の場合は反射色と屈折色を計算し、それを混ぜ合わせる必要がある。1. 反射色 2. 屈折色 3. フレネルの方程式 を適用する。
- 反射方向の計算。物体との好転の法線と主光線の方向が必要となる。反射方向を計算したら、その方向に新しい光線を発射する。もしこの反射光が別の物体(赤い球)にぶつかったとすると、Appelのアルゴリズムを使用して影光線を照射することにより、赤い球のそのポイントに到達する光の量を調査する。これにより色が得られ、ガラス玉の表面に戻る。
- 屈折の計算。光線はガラス玉を通過する(透過光線)。等価方向を計算するためには、物体との交点、主光線の方向、材料の屈折率を使用する。新しい方向が計算させると、屈折光線はガラス玉の反対側へと進む。ガラス玉の反対側に進むtお、光線はもう一度屈折する。空気の屈折率は1.0、ガラス玉の屈折率は1.5であるため、わずかに曲げる必要がある。上記の図において、屈折後の光が緑色の弾に当たるとする。緑色の球と屈折した光線の交点において影の光線を使用して明かりを計算する。
- 最後にフレネルの方程式を適用する。ガラス玉の屈折率、主光線との交点の法線の間の角度が必要となる。
アルゴリズムの疑似コードを以下に示す。
// compute reflection color color reflectionCol = computeReflectionColor(); // compute refraction color color refractionCol = computeRefractionColor(); float Kr; // reflection mix value float Kt; // refraction mix value fresnel(refractiveIndex, normalHit, primaryRayDirection, &Kr, &Kt); // mix the two color glassBallColorAtHit = Kr * reflectionColor + (1-Kr) * refractionColor;
このアルゴリズムは再帰的であり、例えば上記の例において赤と緑の球もガラス玉であるとすると、反射光線と屈折光線によって返される色を見つけるためには、何度も同じプロセスを実行する必要がある。このままでは何度も再帰的に処理が進んでしまうため、深さがある一定再帰深度よりも大きくなった場合には単純に再帰プロセスを停止する。