以前からレイトレーシングをやってみたいと思っていたので、正月の連休を使って『週末レイトレーシング』という本を読んだ。
C++ を使ってフルスクラッチでレイトレーサーを実装していくという内容で、タイトルの通り週末にやりきれる分量にまとめられている。
レイトレーシングのついでに Go の練習もしたかったので、C++ のコードを参考に Go で実装した。
最後まで実装できる確証もないまま始めてしまったが、interface など必要な機能が一通り揃っていたおかげで問題なく実装できた。
ただ、C++ と違って演算子のオーバーロードができないため、ベクトル計算の部分は記述量が多くなってしまい少しつらかった。
以下はレイトレーサーが実装されていく過程。
画像 | 説明 |
---|---|
![]() |
まずは画像の出力。この本では PPM 形式の画像を扱う。 中身はプレーンテキストなのでプログラムで簡単に生成できる。 |
![]() |
ただのグラデーションに見えるが実際にはレイを飛ばしており、背景だけが見えている状態。 当たった部分のY座標に応じて色を変えている。 |
![]() |
球を配置し、衝突したレイに対して法線マップを表示する。 |
![]() |
複数オブジェクトの配置を実装。 下に大きな球を配置して地面っぽくしている。 |
![]() |
アンチエイリアスの実装。 1ピクセルの中のさらに細かいレベルでレイを飛ばして、それぞれの値の平均を取る。 こうやって実装するのか〜と個人的に感動したポイント。 |
![]() |
拡散反射を実装。 光が吸収されて影ができている。 いきなりそれっぽくなって楽しい。 |
![]() |
ガンマ補正を実装。 |
![]() |
シャドウアクネを防ぐ実装。 1つ前の画像と比べるとノイズっぽい影がなくなっていることがわかるはず。 |
![]() |
鏡面反射を実装。 個人的にはレイトレーシングといえばこの綺麗な反射だよねという感じ。 ここらへんのマテリアルを実装する部分は特に楽しかった。 |
![]() |
鏡面反射にぼやけ度のパラメータ (Fuzziness) を実装。 |
![]() |
誘電体 (ガラスマテリアル) を実装。 |
![]() |
カメラの位置を向き先を自由に設定できるように実装。 |
![]() |
被写界深度 (焦点ボケ) を実装。 |
そして最終的にできたのが下の画像。このシーンは本の表紙にもなっている。
まさかここまでの実装だけでこんな綺麗な画像ができるとは思っていなかったので、とても感動した。
(マシンのスペックがショボい上に、並列化などの工夫もしていなかったため生成に2時間近くかかってしまったが…)
読んだ感想としては、「週末に実装できる」という気軽さでこれだけ楽しめる内容になっているのは良いなと思った。
自分の場合は数式の意味を確認しながらちまちま進めたので数日かかったが、単に写経するだけなら本当に週末だけで終わりそうだ。
また、この本ではレイトレーサーの機能を実装するときに、「いろんな実装がありますが、このような実装にしておくと便利です」ということを筆者の経験から説明してくれるので、実装に信頼感 (いろいろ考え抜かれた実装になっているのだなという安心感) が持てるようになっているのも良かった。
ソースコードはこちら。トータルの行数としては300行くらい。
コードを見るとわかるが、C++ から雑に移植しただけなのでたくさん改善の余地がある。
例えば…
- goroutine を使って処理を並列化したい
- Hitable インターフェイスや球、マテリアルなどを別ファイル/パッケージに分割したい
- ベクトルクラスの実装はサボって golang/geo を使ったが、自分で実装してみたい
- Go らしく書けていない箇所があるので直したい
など。
ちなみに、この本は Ray Tracing in One Weekend Series (三部作) の第一巻とのことだった。
第二巻、第三巻の日本語訳は無いようだが、英語版は CC0 ライセンスで公開されているので無料で読むことができる。
上に書いた点を修正できたらぜひ続きをやってみたい。
(そしてレイトレーシングでよく見る箱の中にガラス玉が置いてあるシーンを実装してみたい…)