3次元グラフィックの描画方法の一つであるレイトレーシング。光の反射・屈折などが正確に計算できる手法で結構キレイに画像生成ができます。ただし、間接光が計算できないので、暗めの画像になってしまいます。本ブログでも、Scalaで実装したレイトレーシングで描画した画像を載せていましたが、実は今までレイトレーシングよって生成される画像の各ピクセルの色の計算を結構適当に計算していました。今回は、この色の計算について考えてみたいと思います。
簡単にレイトレーシングの仕組みについて復習してみましょう。現実の世界で、光源から発せられた光が目に届くまでには、いろんな物体に何回も衝突し、その一部が目に届きます。写真のような画像を作りたければ、光源が発せられた全ての光の道筋を計算すればよいことになります。でも、光源からの光の道筋を全て計算しても、最終的に目に届く光というのは、ごく一部です。ほとんど無駄な計算になります。コンピュータの使えるリソースは、限られているのに無駄な計算を何日もかけて計算する気にはなりません。もっと効率的に計算できる方法はないか。ちょっとぐらい写真画質じゃなくてもいいよ。と思った人が、たぶんレイトレーシングという効率的な方法を考えだしたんでしょう。
光源から光を追跡したら、膨大な計算量を必要とする上に、目に届くのは一部。じゃあ、目に届いた光だけを逆に追跡すればいいんじゃね。そう考えたんですね。目に届いた光というのは、スクリーン上のある点と目のある点を結ぶ半直線です。つまり、光源からの光を追跡するんじゃなくて、目がある位置からスクリーン上のある点を通過する半直線(光線=レイ)を追跡(トレース)しようってわけです。これがレイトレーシング(光線追跡)です。光源からの光は無数にありますが、目からの光線は、目がある場所からスクリーン上の各ピクセルとを結ぶ半直線のみなので、ピクセル数の光線を追跡するだけで済みます。
これで、目に届く光だけを計算することができます。目から出た光線は、シーンの中にあるいろんな物体にぶつかって、材質によって反射したり屈折したりして、ある光線は、光源にぶつかり、ある光線は、どこにもぶつからずに闇に消えていきます。光源にぶつかった光線は、その光線が通過したスクリーン上の点を明るくするでしょう。どこにもぶつからなかった光線は、その光線が通過したスクリーン上の点を明るくすることはありません。このようにして、各ピクセルの色が決められていきます。なので、物体表面の反射や屈折を計算して、どの光線が光源とぶつかるかを計算するのが重要になってきます。光線の反射や屈折の計算は、鏡や透明なガラスなどの材質だったら簡単です。では、ざらざらな表面の場合は、どうでしょう?ざらざらした表面は、光が乱反射します。ちなみに、このような性質の表面を拡散面と呼ぶようです。拡散面では、光線は、いろんな方向に反射します。鏡みたいに一方向に反射しません。ん?ちょっと待てよ。色んな方向に反射する?ということは、無数に分散する光線を追跡していかなきゃならんのですね。これじゃ、光源から発せられた光線を追跡するのと変わらんやん!だめやん。振り出しに戻ったやん。と思ってしまうかもしれませんが、レイトレーシングでは、拡散面にぶつかったら、そこで光線の追跡終えます。これがレイトレーシングが正確にピクセルの色を計算できないとこです。では、どうするのかというと、拡散面にぶつかった光線のピクセルの色は、拡散面の位置と光源の位置から近似計算します。間接光の計算はしません。間接光を計算するには、拡散面で分散した光線を追跡しなければならないからです。ちなみに、この追跡を統計的に行うのがパストレーシングです。ということで、レイトレーシングは、拡散面は近似計算で鏡やガラスなどの材質は、正確に計算するレンダリング手法です。
先程も、拡散面では近似計算して、ピクセルの色を計算すると言いました。ここでは、具体的にその計算方法を考えてみます。以下のピクセル値の計算は、僕が勝手に近似計算しているだけなので、よりよい方法があるかもしれませんし、間違っているかもしれません。あしからず。
拡散面から来る光の量を計算を簡単にするために、光の量の種類を2つに分類します。1つは、光源から拡散面に届く光の量で、2つめは、拡散面から目に届く光の量です。
次に、拡散面から目に届く光の量を考えます。拡散面に入射した光の量の一部が目に届きます。拡散面なので、この面に入射した光が全て目に届くはずがありません。そのごく一部の光が目にとどきます。正確には目に届く光は、ちょうど目のある位置の方向に偶然反射した光だけです。したがって、拡散面で反射する光が、どの方向にも一様に反射すると仮定すると、目に届く光の量は、拡散面に入射した光の量を半球面の面積で割った量だけになるはずです。ここで半球面の半径は、拡散面上の点から目の位置までの距離です。
それに対して、鏡で反射して目に入ってくる光は、鏡のその点に入射した光が全て同じ方向(目がある方向)に反射した光です。なので、この場合は、半球面の面積で割る必要がありません。
レイトレーシングで描画した結果です。この画像をみる限り、光の量の計算は、よい近似になってるのではないでしょうか。
レイトレーシングの復習
簡単にレイトレーシングの仕組みについて復習してみましょう。現実の世界で、光源から発せられた光が目に届くまでには、いろんな物体に何回も衝突し、その一部が目に届きます。写真のような画像を作りたければ、光源が発せられた全ての光の道筋を計算すればよいことになります。でも、光源からの光の道筋を全て計算しても、最終的に目に届く光というのは、ごく一部です。ほとんど無駄な計算になります。コンピュータの使えるリソースは、限られているのに無駄な計算を何日もかけて計算する気にはなりません。もっと効率的に計算できる方法はないか。ちょっとぐらい写真画質じゃなくてもいいよ。と思った人が、たぶんレイトレーシングという効率的な方法を考えだしたんでしょう。
光源から光を追跡したら、膨大な計算量を必要とする上に、目に届くのは一部。じゃあ、目に届いた光だけを逆に追跡すればいいんじゃね。そう考えたんですね。目に届いた光というのは、スクリーン上のある点と目のある点を結ぶ半直線です。つまり、光源からの光を追跡するんじゃなくて、目がある位置からスクリーン上のある点を通過する半直線(光線=レイ)を追跡(トレース)しようってわけです。これがレイトレーシング(光線追跡)です。光源からの光は無数にありますが、目からの光線は、目がある場所からスクリーン上の各ピクセルとを結ぶ半直線のみなので、ピクセル数の光線を追跡するだけで済みます。
これで、目に届く光だけを計算することができます。目から出た光線は、シーンの中にあるいろんな物体にぶつかって、材質によって反射したり屈折したりして、ある光線は、光源にぶつかり、ある光線は、どこにもぶつからずに闇に消えていきます。光源にぶつかった光線は、その光線が通過したスクリーン上の点を明るくするでしょう。どこにもぶつからなかった光線は、その光線が通過したスクリーン上の点を明るくすることはありません。このようにして、各ピクセルの色が決められていきます。なので、物体表面の反射や屈折を計算して、どの光線が光源とぶつかるかを計算するのが重要になってきます。光線の反射や屈折の計算は、鏡や透明なガラスなどの材質だったら簡単です。では、ざらざらな表面の場合は、どうでしょう?ざらざらした表面は、光が乱反射します。ちなみに、このような性質の表面を拡散面と呼ぶようです。拡散面では、光線は、いろんな方向に反射します。鏡みたいに一方向に反射しません。ん?ちょっと待てよ。色んな方向に反射する?ということは、無数に分散する光線を追跡していかなきゃならんのですね。これじゃ、光源から発せられた光線を追跡するのと変わらんやん!だめやん。振り出しに戻ったやん。と思ってしまうかもしれませんが、レイトレーシングでは、拡散面にぶつかったら、そこで光線の追跡終えます。これがレイトレーシングが正確にピクセルの色を計算できないとこです。では、どうするのかというと、拡散面にぶつかった光線のピクセルの色は、拡散面の位置と光源の位置から近似計算します。間接光の計算はしません。間接光を計算するには、拡散面で分散した光線を追跡しなければならないからです。ちなみに、この追跡を統計的に行うのがパストレーシングです。ということで、レイトレーシングは、拡散面は近似計算で鏡やガラスなどの材質は、正確に計算するレンダリング手法です。
拡散面に届く光の量と目に届く光の量
先程も、拡散面では近似計算して、ピクセルの色を計算すると言いました。ここでは、具体的にその計算方法を考えてみます。以下のピクセル値の計算は、僕が勝手に近似計算しているだけなので、よりよい方法があるかもしれませんし、間違っているかもしれません。あしからず。
拡散面から来る光の量を計算を簡単にするために、光の量の種類を2つに分類します。1つは、光源から拡散面に届く光の量で、2つめは、拡散面から目に届く光の量です。
拡散面に届く光の量の近似計算
目に届く光の量の近似計算
次に、拡散面から目に届く光の量を考えます。拡散面に入射した光の量の一部が目に届きます。拡散面なので、この面に入射した光が全て目に届くはずがありません。そのごく一部の光が目にとどきます。正確には目に届く光は、ちょうど目のある位置の方向に偶然反射した光だけです。したがって、拡散面で反射する光が、どの方向にも一様に反射すると仮定すると、目に届く光の量は、拡散面に入射した光の量を半球面の面積で割った量だけになるはずです。ここで半球面の半径は、拡散面上の点から目の位置までの距離です。
それに対して、鏡で反射して目に入ってくる光は、鏡のその点に入射した光が全て同じ方向(目がある方向)に反射した光です。なので、この場合は、半球面の面積で割る必要がありません。
描画結果
レイトレーシングで描画した結果です。この画像をみる限り、光の量の計算は、よい近似になってるのではないでしょうか。
0 件のコメント:
コメントを投稿