レイトレーシング(5): 物体の定義
前回までで、光源から放射されるフォトンが生成できたので、次はそれを 追跡してフォトンマップを作ることになるが、そのためには描かれる「物体」を 準備しないといけない。
「物体」定義
次に考える処理は、メインルーチン中の次の部分だ。
photoncaches <- tracePhotons objs photons
objs
はシーン中の物体のリスト、photons
は前回生成したフォトンのリストである。
だから、tracePhotons
の処理を考える前にobjs
がどういうものかを定義する必要がある。
本プログラムでは物体をObject
型で定義しよう。物体に必要な情報は何だろうと考えると
「形」と「材質」だろう、と考えてみた。今後他にも出てくるかもしれないが、今は
その二つにしておく。
data Object = Object Shape Material
材質は木とかガラスとかで、情報としては物体の色や反射率、透明度などなどだ。 考え出すととても複雑な構造になるが、まず作ろうとしている"バージョン1"では 物体は「表面が拡散反射のみ」で「フォトンの追跡は反射を無視」としたのだった。 だからフォトンの追跡は「物体にぶつかったらその位置を記録して終わり」という ことになる。実はこれだとフォトンマップを作るためには材質として何の情報も要らない のだが、あとあとレイトレーシングで画像を作る段になったらさすがに色の情報が 必要なのでその分だけ定義しておこう。「拡散反射率」だ。
data Material = Material Double Double Double
3つのDouble
は赤緑青それぞれの波長での拡散反射率を表す。0から1の間の数値を
設定する。色や輝度をどのような型で表すかまだ決めていないが、その検討次第では
型コンストラクタの引数は型が変わるだろう。
さて、今大事なのは「形」の方だ。レイトレーシングでは、無限平面や球面、二次曲面、 ポリゴンなど様々な「形」が使われる。光源と同じだ。光源の定義では失敗したので、 形の定義では最初から多相性を意識して定義しよう。ただしひとまず無限平面と球面のみ 扱うことにする。(ちょっと先のことも考え、大きさのない"点"も入れておくが)
data Shape = Point Position3 | Plain Direction3 Double | Sphere Position3 Double
ここで、無限平面と球面は次の方程式を満たす三次元空間中の点
(位置ベクトル)の集合である。
ここで、は平面の法線ベクトル、
は平面の位置に
関係するパラメータ、
は球の中心座標、
は球の
半径だ。このあたりの詳しいところはその筋の文献などを参照のこと。たとえば、

- 作者: Fletcher Dunn,Ian Parberry,松田晃一
- 出版社/メーカー: オライリージャパン
- 発売日: 2008/10/04
- メディア: 大型本
- 購入: 21人 クリック: 141回
- この商品を含むブログ (40件) を見る
などに記載がある。上記のPlain
とSphere
の型コンストラクタの引数は、それぞれ
と
である。
「形」に必要な関数
フォトンの追跡は、まず物体と衝突する場所(交点)を求めることから始まる。
バージョン1では反射は考えないので交点計算がやることのすべてと言っていい。
Shape型は上記の通り方程式で記述できるので、交点を求めるのは容易だ。光線(Ray
)
との連立方程式を解けばよい。交点を
とすると、
連立させて
を求めれば、位置
も解るわけだ。
よって、
を計算する関数
distance
を用意しよう。
distance :: Ray -> Shape -> [Double] -- Point distance r (Point p) = [] -- Plain distance (pos, dir) (Plain n d) | cos == 0 = [] | otherwise = [(d + n <.> pos) / (-cos)] where cos = n <.> dir -- Sphere distance (pos, dir) (Sphere c r) | t1 <= 0.0 = [] | t2 == 0.0 = [t0] | t1 > 0.0 = [t0 - t2, t0 + t2] where o = c - pos t0 = o <.> dir t1 = r * r - (square o - (t0 * t0)) t2 = sqrt t1
交点がない場合、複数の場合があるので、結果はのリストとする。
今後反射や屈折を考えたり、輝度計算をするときには交点での法線ベクトルを求める 必要が出てくる。今はいらないが簡単なので定義しておこう。
getNormal :: Position3 -> Shape -> Maybe Direction3 -- Point getNormal p (Point p') = Nothing -- Plain getNormal p (Plain n d) = Just n -- Sphere getNormal p (Sphere c r) = normalize (p - c)
「点」の場合法線ベクトルがないので、関数getNormal
の結果をMaybe
型に
している。