IQが1: または、”IQが1″をレンダリングするまでの道程

IQが1 Advent Calendar

IQが1は、IQが1に覆いかぶせるように立てられた収容棟内部に収容されています。

IQが1でした

よろしくおねがいします


 

おはようございます。aktzkです。この記事は、以下より

rogy Advent Calendar 2017

の7日目の記事です。IQがなんとかかんとかとは全く関係が無いので、そこから来たあなたは即時戻るボタンか☓を押しなさい。押して下さい。

 


“IQが1″をレンダリングするまでの道程

レイトレーシングをしようと思いました。今年のGWくらいの時期の話です。

上の画像が出来るまでを振り返ります。

これは現実逃避です。研究とはかくも辛き事なりと古事記に書いてある

使用言語

Rustです。少なくともオレオレ目線では、C++に比べて他人と自分のコードが見やすい、書きやすい、外部ライブラリ導入しやすい、外部ライブラリのドキュメンテーションにアクセスしやすい上に見やすい等良いことだらけです。言語仕様的な利点については言語のプロさんに聞いて下さい。

初日

レイを飛ばして物体と衝突した時、その物体の衝突した点の微少平面の法線を返して、それを出力します。満足しました。

何やってたんだろ……イカかな……

満足してませんでした。作り直して、よりリアリスティックな画像を出力しようと試みます。

レンダリング方程式なる積分方程式の結果をモンテカルロ法(乱数を使って数値計算する手法です)を用いて近似します。

バグです

バグりました。恐らく画像中央の円錐を構成する三角形メッシュに対するBVH木構造の構築過程に何らかのバグがあります。

 

この時点で、衝突判定に外部ライブラリを利用することにしました。 ncollide_geometry です。

 

 

 

 

 

次に、被写界深度効果を実装しました。一枚のレンズを想定して、レンズ内の点をランダムに決定し、飛ばす方向を決めるだけです。上の画像を見比べると分かりやすいと思います。

以上から、右の様な画像を生成することが出来ました。

 

 

 

 

 

この時点まで物体に当たった光はランバート反射すると断定して実装していました。次に多様な反射・屈折(要するに多様な物体の表面材質)を取り扱えるようにしました。

これの実現においては、衝突面から入射、出射する光の方向を接ベクトル空間上のベクトルで扱う必要があります。簡単に言えば衝突面の法線が(0,0,1)であるような座標系です(接線を慎重に選ぶ必要がある)。

後、テクスチャマッピングのために物体のUV座標も必要です。

ncollideからレイを扱うクレート ncollide_geometry は衝突情報として法線しか持ってこないものだったので、ncollide_geometryだけ自分のコードに引っ張ってきてuv座標と接線を返すように書き換えました(一部のジオメトリ)。

以上と諸々により形成されたダークマターです。

 

 

もちろんバグです。円の内部で衝突判定が完結し続けていました。

 

こちらは上手く行った方の、ガラスのような材質の物体です。スペキュラ反射と屈折の度合いをフレネルの式によって決定しています。

 

 

テクスチャマッピングです。ここアルベドを衝突面のuv座標からサンプルしたテクスチャ上の色(単色ならば単色という感じに)としています。奥の方ではガラスの四角形が漂っています

 

 

コーネルボックスを作りました。(実はこの画像はおかしい)

 

 

 

 

 

 

 

アドベントカレンダーのために、レンダリングしたい物体をBlenderで作成しました。

文字のように見えますが、私には何と書いてあるのか分かりません。

 

セッティングしています。

 

 

 

そして、最終的にこのような画像が得られました。4コアのCPUで並列計算し(rayonはすごい)、画素の中を1024回サンプル、光線の反射回数を約8回に抑えて、18分ほどかかりました。上手く行ってると思います。

 

終わりに

ソースコードは以下に公開しました(が、殆ど私的なコードなのでドキュメンテーションはありません)。リリースビルドを強くおすすめします。現在開発中であり、これからも作り続ける(と言うよりは勉強する)予定なのですが、現在は研究が忙しく手がつかない状況です。卒業したいです。

loor_ray

参考

世間話

xenoblade2にも時間を吸われてます。世界観と物語に没入出来るようなゲームをしたのはかなり久し振りだったので感銘を受けました。ニアchangkawaii

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です