WebGLパストレーシングを技術書典2のためにブラッシュアップ

4/9(日)にアキバ・スクエアで開催される技術書典2に参加します。 技術書典は技術書のみを扱うコミケようなイベントです。

去年に引き続き、技術サークルTechBoosterのWeb本の著者のひとりとして参加します。

今回は『Think Web』の『第6章 まるで実写!?GPUパストレーシングのWebGL実装』を担当しました。

Think Webの表紙

パストレーシングとは?

パストレーシングは3Dの描画手法のひとつで、現実世界に近い光の振る舞いをシミュレートすることで、大域照明を考慮した写実的なレンダリングを可能にします。 実際にハリウッド映画などの写実的なCGの多くには、パストレーシングやパストレーシングを発展した手法が採用されています。 写実的なレンダリングができる反面、処理時間が膨大にかかるという弱点があります。

本の内容

私の章ではパストレーシングのGPU実装による高速化について紹介します。 しかも単純な高速化ではなく、ブラウザ上で3DCGを扱うWebAPIであるWebGLによりGPU実装することで、 ブラウザ上で動作するインタラクティブなパストレーシングを実現します。

去年12月のWebGLのアドベントカレンダーのQiita記事と同じテーマですが、内容を大幅に加筆・変更しています。 Qiitaには書ききれなかったパストレーシングの基礎や原理の部分から説明し、実際のコードを踏まえながら実装についても丁寧に解説しました。

なるべく敷居を下げるために専門用語を解説しつつ、説明が長く過ぎず短すぎず丁度いい分量になるように意識して執筆しました。 読者ターゲットは、単純なレイトレーシングは分かっているけれども、パストレーシングは難しい…という人を想定しています。

WebGLパストレーシングのデモ

開発したWebGLパストレーサ(パストレーシングのプログラム)はブラウザ上で動かせるので、良ければ触っていただけると嬉しいです。

シーンエディット機能を搭載しており、オブジェクトの位置やスケール、マテリアルをリアルタイムに編集・プレビューできます。 マテリアルのBRDFとしては完全鏡面反射・完全拡散反射・GGX・屈折面に対応しています。 マテリアルのColor / Roughness / Emissionにはテクスチャを指定することもできます。

技術書典2のためのブラッシュアップ

執筆にあたってコードを見返したところ、様々なバグを見つけたので、原稿と平行してバグ修正に取り組んでいました。 睡眠時間と引き換えにして、なんとかバグを取り除き、レンダリングの品質を大きく改善できました!

この記事では、本の宣伝もかねて「どのようなミスがあり、どのように修正をしたのか」を簡単に紹介します。

原稿を書くのは大変ですが、思考とコードを整理できたので、個人的に得るものが大きかったと感じます。

修正箇所一覧

以下が修正箇所です。

  • バグ修正
    • 完全拡散反射で半球外をサンプリングさせない(法線を基準とした直交座標の基底ベクトルを決定する処理に不具合があった)
    • GGXによる反射方向のサンプリング時に半球外が選ばれた時の例外処理(強制的にBRDF=0する)
    • レンダリング方程式に基き、再帰の処理をループに書き換える方針にミスがあったので修正(GLSLは再帰ができないので、末尾再帰をループに置き換える必要があるが、置き換え方が間違っていた)
  • 機能追加
    • 屈折面ではフレネルの式から反射率を計算する(去年の段階では 100%反射 OR 100%屈折 のみだった)
    • ガンマ補正をちゃんとする
      • テクスチャを参照するときは逆ガンマ変換
      • スクリーンに出力するためのRenderTargetに書き込むときはガンマ変換
    • 簡単なアンチエイリアシング
      • レイを飛ばす前のスクリーン座標に-0.5〜0.5の範囲の乱数を加える
  • その他
    • 環境マップの追加(夜のお城)
    • プリセットのシーンの追加(コーネルボックス)
    • 最適化・リファクタリング

詳細はPRをご覧ください。

結果

ブラッシュアップしたパストレーサのレンダリング結果を紹介します。

世界地図の光源

暗いシーンの背後に照明を置いたシーンです。 屈折面の付近にコーティクス(集光模様)を観察できるなど、間接光も反映した大域照明を実現できました。

IBLよりも背後の光源の影響が強いシーンですが、ノイズが消えてコーティクスなども鮮明にレンダリングできています。 ノイズが消えたのは、BRDF周りのバグ修正により半球外のサンプリングをするケースを取り除くことができた影響です。

屈折面では反射と屈折の両方をトレースするようになったので、ガラス面も薄っすらと鏡面反射するようになりました。

マテリアルのテスト

同じ色(白)・同じ大きさで材質だけが異なる4つの球体を配置したシーンです。 左から順に(1)完全拡散反射面、(2)完全鏡面反射面、(3)屈折面(ガラス面)、(4)微小な凹凸のある鏡面(GGX)です。 シーンの上部の白い球体が光源です。

コーネルボックス

コーネルボックス風のプリセットシーンを追加しました。 残念なことに、現在の実装ではコーネルボックスのような光源が小さくIBLができないシーンのレンダリングは苦手で、ノイズが消えるまで数分間かかります。 レンダリング方程式の cos 項に比例した重点サンプリングはしているものの、高速化の工夫をしていない純粋なパストレーシングのためです。 小さな光源しかないシーンを高速にレンダリングするためには,まだまだ課題が残っています… (とはいえ、もちろん時間をかければスクリーンショットのように綺麗な結果になります!)

テーブル

箱を積み重ねたテーブルのシーンです。前回と同じシーンですがノイズが完全に無くなりました。

今後やりたいこと

  • コーネルボックスのような光源が小さいシーンの収束が遅すぎるので、Next Event Estimationをする
  • 準モンテカルロ法
  • 屈折面において、屈折時の立体角の変化による放射輝度の変化を考慮できていない点の修正
  • 箱と球体以外のプリミティブに対応させる
  • どんなに良いGPUを使っていても、1秒間に60サンプリングに制限されてしまう仕様なので、GPU性能に合わせて単位時間あたりのサンプリング数を増減できる仕組み

最後に

技術書典2と『Think Web』を宜しくお願いします!

以下のようなテーマについて、各技術のスペシャリストが全力で執筆しています。

  • Rust+WebAssembly、Flutter などマルチプラットフォーム技術
  • Vue.js、GopherJS、WebGL など最新フロントエンド技術の解説
  • Google Cloud Datastore などデータベース関連技術

自分の章はニッチすぎると思いますが、明らかに1000円以上の量と質のあるお得な本になっていると思います!

お時間がありましたら、ぜひいらしてください!

comments powered by Disqus

gam0022.net

Qiita

Hatena Blog

gam0022.net

Qiita

Hatena Blog