※この記事ではgitのタグ「v2.75」から生成したブランチ上でコードリーディングしています。
Blender標準のレンダラよりもリアルな絵を作る事の出来る「Cycles」というレンダラ。アーティストの方々はクオリティ・リアリティの高い画像や動画などを作る際に利用されている事でしょう。数あるBlenderの機能の中でも注目度が高いのではないでしょうか?
プログラマである私のBlenderの使い道と言えばメッシュを作ったりボーンを仕込んだりしてゲーム開発の際のテスト用モデルを作る事であり、Cyclesのお世話になる事はなかったのですが、コードリーディングをしてみようと思い立ち1から勉強してみることにしました(なんだか目的と手段が逆な気もしますが ^_^; )。
Cyclesはとても奥深い機能であるし、現在も開発が進んでいます。ですのでこのCyclesの記事は1回では終わりませんし、part何までいくか今のところ分かりません。もしかしたら途中で別の機能についての記事を挟んでまた再開するようなこともあるかもしれません。とにかく頑張ってコードリーディングしていこうと思いますのでお付き合いいただければ幸いです。
まずはじめに、「Cyclesとは〜〜だ!」と一言で説明されたものを頭に入れておけば後々理解の助けになりそうです。そこでBlender Reference ManualのCyclesのイントロダクション から引用します。
Cycles is a ray tracing renderer focused on interactivity and ease of use, while still supporting many production features.
要するに肝心なところは「Cyclesとはレイトレーシングレンダラだ!」というところですね!
しかしこの「レイトレーシング」、ちょっと調べてみると指しているものが広すぎてもう少し整理しないことには理解の助けにならない事が分かったのです。
ここから先は上記の「レイトレーシング」が何を指すのかもう少しハッキリさせるべく、歴史的なところから調べた事を書いていますが、それぞれのキーワードについて厳密な定義が存在するのかはわかりません。故に私よりも深く勉強されている方からは指摘されるような部分があるかもしれませんが、このように解釈すればCyclesの理解に役立つだろうという部分に主眼を置いて自分なりに整理してみました。
「レイトレーシング」(便宜上、古典的レイトレーシングと呼ぶ事にします。)が考案されたのは1980年代の初頭だったそうです。古典的レイトレーシングは光源から放出される光が物体に直接及ぼす影響しか考慮されていなかったようです。
上記の英文がさす"ray tracing"とは「古典的レイトレーシング」のことなのでしょうか?
実際にCyclesを使ってみるとそうではなさそうだという事が分かります。
床のオブジェクトにトーラスの色が少し映り込んでいるのが分かります。トーラスと床のマテリアル設定はノードの示す通りで光源として設定されている訳ではなく、Diffuseとなっています。つまりCyclesは光源からの直接の影響だけではなく、他の物体が反射した間接的な光も影響するように出来ているようです。このような現象は「間接照明」と呼ばれ、間接照明まで考慮して物体表面の光の挙動をモデル化したものを「グローバルイルミネーション」と呼ぶそうです。
「古典的レイトレーシング」は「間接照明」を考慮していないので「グローバルイルミネーション」には含まれませんが、1984年頃に「古典的レイトレーシング」を発展させる形で「間接照明」まで考慮されたレイトレーシングが考案されたようです。それが「分散レイトレーシング」と呼ばれるアルゴリズムです。「分散レイトレーシング」では1本のレイが物体に入射すると複数のレイが反射されるようです。
しかしこの「分散レイトレーシング」にはレイの数が膨大になる事やその他の欠点があるようで、これらの問題を解消する形で「パストレーシング」というアルゴリズムが1986年頃に考案されました。
その後、1990年代になると視点からのレイも光源からのレイも両方追跡する「双方向パストレーシング」というアルゴリズムが考案されます。
今後書く記事の中で詳しく触れようと思いますが、Cyclesのレンダリング部分のコードを追いかけてみると、kernel_path_traceという名前の関数にたどり着きます。この関数の名前が「パストレース」「双方向パストレース」のどちらを指すのかは今のところわかりませんので後々探っていく事となりますが、ここまでで「レイトレーシングという言葉の指すものが広すぎてもう少し詳しく見ないとCyclesを理解する上で助けにならない」といった意味がおわかりいただけたかと思います。
長い説明になってしまったので、ここまでの私の見解を大まかに図に表しておきます。
さて、ゲームのように秒間に何十フレームもレンダリングする必要のある場合、その技術はリアルタイムレンダリングというカテゴリに分類されて、多くはラスタライジングという手法が採用されます。ラスタライジングはプリミティブ単位でレンダリングする手法です。
一方、何秒・何分・モノによっては何時間もかけて1フレームをレンダリングする事を繰り返し、予め画像や動画などを仕上げておく技術をプリレンダリングと呼びます。レイトレーシングがリアルタイムレンダリングで採用される例は現時点では少なく、多くはプリレンダリングにおいて使われます。
レイトレーシングはラスタライジングと違い、ピクセル単位でレンダリングされます。その事をCyclesのコード上で確認してみましょう。
GPUを使う設定をしていないのであれば、Cyclesでレンダリングをする際に
Sources/cycles_device/Source Files/device_cpu.cppの
for(int y = tile.y; y < tile.y + tile.h; y++) {
for(int x = tile.x; x < tile.x + tile.w; x++) {
path_trace_kernel(&kg, render_buffer, rng_state,
sample, x, y, tile.offset, tile.stride);
}
}
という部分を通ります。
どうやらタイル状に区切ってピクセル単位でレンダリングしているような雰囲気がありますね。レンダリング結果はこうなります。
tile.hとtile.wを2で割ってみたらどのようにレンダリングされているのかわかりやすい絵が出来そうですね。レンダリング結果はこうです。
ご覧の通りタイル状に区切られてピクセル単位でレンダリングされています。プリミティブ単位でレンダリングされるラスタライジングとは違うのがわかります。
レイトレーシングの歴史を調べるにあたり、こちらの本を参考にさせていただきました。
KLabのゲーム開発・運用で培われた技術や挑戦とそのノウハウを発信します。
合わせて読みたい
KLabのゲーム開発・運用で培われた技術や挑戦とそのノウハウを発信します。