はじめに
こんにちは、近頃Web系に浮気していた@yoship1639です。
皆様は楽しい3Dプログラミングライフを如何お過ごしでしょうか。
私はWebを最近触り始めたのがきっかけで、Docker+Three.jsでPBRやレイトレをぼちぼち行っています。
ところで皆様こんな悩みをお持ちではないでしょうか
「DirectX9時代の3Dはなんとなくわかるけど、最近のは複雑怪奇すぎて全然知らない」
「ああレイトレね、完全に理解してるわー(よくわかっていない)」
そんなあなたに最近の3DCGで何が流行っていてそれが何を解決しているのかを、なるべく分かりやすく掻い摘んでご紹介したいと思います(中には10年程前の手法もありますが現役の手法なので紹介します)。これから紹介する技術や用語を駆使することで、近年の美麗な3DCGを再現することができるようになります。
理解しやすくするため、詳細な技術要素やアルゴリズムは省き、概要・解決できる事を中心に紹介します。近年の3DCGの事をざっくり知りたい方が対象なので、詳細な内容を知りたい方は参考リンクをご覧ください。
「知っていた方がいい度」なるものをつけますが、あくまで私の主観なので目安程度にしておいてください。
技術・用語紹介
※各画像はaltに記載したアドレスページから引用しています。
物理ベースレンダリング - Physically Based Rendering: PBR
知っていた方がいい度:★★★★★
流行っているというより、リアル系の3DCGではデファクトスタンダードですね。
このレンダリング手法を用いると、従来のCGっぽさが薄れて物理現象に基づいたリアリティのある表現が可能となります。
これ以前のレンダリング(LambertやPhongなど)は見た目がなんとなく良くなる様な数学的な近似値でもって色を出力していましたが、物理ベースレンダリングは名前の通り現実世界の物理現象(光の散乱・反射・吸収・屈折、エネルギー保存則など)を忠実に再現し最終的な色を出力するレンダリング手法です。
従来のレンダリングモデルでは、拡散反射色(Diffuse Color)、鏡面反射色(Specular Color)、光沢(Shininess)といったパラメータで材質の特徴を表していましたが、物理ベースレンダリングモデルでは、基本色(Albedo Color)、粗さ(Roughness)、金属度(Metalness)、鏡面反射量(Specular)でもって材質の特徴を表します(※採用するシェーディングモデルによってパラメータが増減します)。そのため、Diffuse ColorやSpecular Colorなるものが材質に存在している場合は、古いレンダリングモデルの特性を表していると思ってください。
物理ベースレンダリングは、物理現象をなるべく厳密にモデル化しシェーダコードに起こすため従来より処理が重くなりますが、それだけ出力される結果も良いものとなります。
参考リンク
双方向反射率分布関数 - Bidirectional Reflectance Distribution Function: BRDF
知っていた方がいい度:★★★☆☆
物理ベースレンダリングと切っても切り離せないのがこのBRDFです。
ざっくり言うと、入射した光がある方向にどの位の割合で放射されるかを表す関数です。
一般的な物理ベースレンダリングモデルはこのBRDFに基づいて計算を行います。(BRDF以外も存在します)
BRDFは拡散BRDFと鏡面BRDFが存在し、この2つの合計でもって最終的な色を出力します。
そして、拡散BRDFと鏡面BRDFは材質の金属度によって加算する割合が変わります。
つまり、物理ベースレンダリングの式は大雑把に言うとこんな感じになります。
m = metallic; // 材質の金属度(0~1)
color = 0; // 色の合計
for (ライトの数) {
color += 拡散BRDF() * (1 - m);
color += 鏡面BRDF() * m;
}
return color;
あら簡単!(※省きまくってるだけでBRDFの式は複雑です)
詳細な内容は解説しないので、詳しく知りたい方は参考リンクをご覧ください。
参考リンク
遅延レンダリング - Deferred Rendering
知っていた方がいい度:★★★☆☆
遅延レンダリングは、フォワードレンダリングと呼ばれる従来の1パス(シェーダプログラムを1度だけ走らせること)による描画を、2パスによる描画に置き換えた描画手法です。なぜわざわざ2パスに分けてしまうのかというと、多数のライトに対応させるためと、後で紹介するポストプロセスと相性が良いためです。
1パス目では、ジオメトリバッファ(G-Buffer)と呼ばれる場所(基本的にテクスチャ)にワールド座標位置やワールド座標法線、基本色、粗さ、金属度等を出力します。1パス目はG-Bufferパスとよく呼ばれます。2パス目ではG-Bufferの情報を元にライティング処理を行い、最終的な色を出力します。2パス目はLightingパスとよく呼ばれます。
遅延レンダリングにすると逆に遅くなりそうと思われるかもしれませんが、処理の重いLightingパスは、多数のオブジェクトが存在したとしても1度だけ実行すれば良いという利点があり(フォワードレンダリングはオブジェクト毎にライティング処理を実行する)、多数のオブジェクトがある場合はむしろフォワードレンダリングより高速になります。
参考リンク
ライトカリング - Light Culling
知っていた方がいい度:★★☆☆☆
ライトカリングは、遅延レンダリングの利点である多数のライトに対応させるための処理です。シェーダは柔軟性が低いため、普通はライトの数だけライティング処理を実行しなければいけませんが、ライトカリングはオブジェクトに当たるライトだけライティング処理を行う事ができるため、1000を超えるライトでも扱うことが可能になります。
ライトカリングには様々な手法がありますが、今回紹介するのはタイルベースライトカリングと呼ばれる手法です。タイルベースライトカリングはCompute Shaderと呼ばれる汎用GPU処理で、画面を区画分けし(よくあるのが16x16マス毎)その区画内に影響のあるライト情報を格納し、ライティング処理時に区画内にあるオブジェクトに適用させることでライトの影響範囲を限定させる処理を行っています。
Compute Shaderによるライトカリングパスが増えますが、大多数ライトに対応させるためであれば何て事はありません。積極的に使っていきましょう。
参考リンク
日本語記事がほぼ皆無でした_(:3」∠)_
マルチプルレンダーターゲット - Multiple Render Target
知っていた方がいい度:★★★☆☆
手法というより最近の3Dライブラリに実装されている機能です。通常シェーダを走らせると結果を1つのテクスチャもしくはバッファに格納しますが、最近のシェーダは1度のシェーダで複数のテクスチャやバッファにそれぞれ異なる結果を格納することができます。マルチプルレンダーターゲットの嬉しいところは、1つのシェーダプログラムで高速に複数のバッファを書き出すことができ、後述のポストプロセスに活かる事ができる点です。
遅延レンダリングのG-Bufferはマルチプルレンダーターゲットによって書き出されます。
Forward+レンダリング
知っていた方がいい度:★★☆☆☆
フォワードレンダリングの弱点である多数ライト対応を解消するために遅延レンダリングそしてライトカリングが登場しましたが、「あれ?ライトカリングってフォワードレンダリングでも使えるよね?」ということで登場したのがForward+レンダリングです。
Forward+レンダリングの利点は、遅延レンダリングの苦手とする複数マテリアルが存在するシーンや複雑なマテリアルを扱う場合でもフォワードレンダリングの強みを活かすことができる点です。
遅延レンダリングとForward+レンダリング、どちらにも利点・欠点があるので、シーンによってどちらを採用すべきか決めるのがよいかと思われます。
参考リンク
こちらも日本語記事がほとんどありません_(:3」∠)_
- FORWARD+: BRINGING DEFERRED LIGHTING TO THE NEXT LEVEL
- Forward vs Deferred vs Forward+ Rendering with DirectX 11
バリアンスシャドウマッピング - Variance Shadow Mapping: VSM
知っていた方がいい度:★★☆☆☆
通常のシャドウマッピングは生成される影がハードでギザギザしてしまいますが、バリアンスシャドウマッピングは確率論で使われる方程式「チェビシェフの不等式」をシャドウマップに適用させる事で、比較的高速に柔らかい影を生成できる優れたシャドウ技法です。画像を見てわかるようにソフトな影が生成されているのが分かります。
バリアンスシャドウマッピング以外にも様々なシャドウ技法が存在しますが、比較的軽く、次に紹介するカスケードシャドウにも対応させる事ができるのでおススメのシャドウ技法です。
参考リンク
カスケードシャドウ - Cascaded Shadow
知っていた方がいい度:★★★☆☆
最近のシャドウではよく用いられる手法です。通常、シャドウはカメラに近い箇所はジャギーが目立ってしまいますが、カスケードシャドウはシャドウマップを複数用意し(プラットフォームによって2~5枚辺り)、カメラからの距離ごとに詳細なシャドウマップから広域のシャドウマップまで降順に書き出します。こうすることで、近くの影は詳細に、遠くの影は詳細でなくても大丈夫なので広域にシャドウマッピングし、従来のジャギーの目立つ影を解消することができます。
この手法は、影の値を算出するアルゴリズムとは別の処理ですので、様々なシャドウ技法に適用させることができます。
参考リンク
イメージベースドライティング - Image Based Lighting: IBL
知っていた方がいい度:★★★★☆
個人的に知っていて欲しい技術です。通常ライトはワールド座標に配置されるライト情報を参照しますが、IBLは環境マップテクスチャをライトとして扱ってしまうライティング処理です。何が嬉しいかというと、オブジェクトの周りにある環境を疑似的に物理パラメータの元にライトとして映りこませる事で、よりオブジェクトがその環境下にある様に馴染ませる事が可能になります。環境マップはHDR(0~1の輝度を超えた値)なテクスチャであるとより効果が増大します。
ライティング処理として、物理ベースシェーダの最後にIBL処理を行う事が多いです。
参考リンク
大域照明 - Global Illumination: GI
知っていた方がいい度:★★★★☆
大域照明は、光の伝搬を物理的に正しく表現するレンダリング技法です。ざっくりいうと、モノの映り込みとか狭い場所に光を届かせるのを再現し、より現実世界の見え方に近づける技法です。
大域照明には様々な手法がありますが、代表的なのはレイトレーシングで忠実に再現してしまうやり方で、よりリアリティが求められる映画やレンダリングソフトウェアには当然のように搭載されています。しかし、レンダリングにとてつもなく時間がかかるため、リアルタイム性が求められるゲームでは、動かないオブジェクトだけ予めライトマップとして焼き付けるという回避策をとります。
もう一つが仮想的にライトを配置してしまう手法(Virtual Point Light)で、光が伝搬するであろう箇所に仮想的にライトを配置し、あたかも大域照明が再現されているかの様に見せる手法です。こちらはリアルタイムでも可能なので、奇麗なグラフィックのゲームには採用されているのではないでしょうか。
参考リンク
動的なGIも着々と研究されているようです
ポストプロセス - Post-Processing
知っていた方がいい度:★★★★★
絶対知ってた方がいいです。なぜかというとポストプロセス適用前と適用後は見た目に雲泥の差が出るからです。
ポストプロセスは、レンダリングを行った後に後付けで効果を加える手法のことを指します。これにより、通常のレンダリングだけでは再現できなかった表現が可能となります。ポストプロセスはとても多くの種類がありますが、その中でも代表的なものをご紹介したいと思います。
以前、ポストプロセスに関するQiita記事を記述したことがあるので、その中の文言をそのまま転載させていただきます。
アンチエイリアス - Anti-Aliasing: AA
知っていた方がいい度:★★★★☆
アンチエイリアス(AA)とは、エイリアシングと呼ばれるピクセル間で起こるギザギザ(ジャギー)が起こらない様に滑らかにする処理の事です。イラスト系でもよく聞く言葉なので、知っている方も多いかと思います。実はこの処理ゲームの描画にもリアルタイムで適用できます。それはFXAA(Fast Approximate Anti-Aliasing)と呼ばれるポストプロセスで、描画された画面を高速でアンチエイリアシングする事が出来ます。FXAAは比較的軽い処理であるのに見た目が簡単によくなるので非常にお勧めです。
参考リンク
アンビエントオクルージョン - Ambient Occlusion: AO
知っていた方がいい度:★★★☆☆
アンビエントオクルージョン(AO)とは、環境光(Ambient)の光が遮られる(Occlusion)ことを言います。わかりやすく言うと、モノとモノの間や角などに光が届かなくて暗く影になる現象の事です。通常の描画処理では影は出来ても濃い影は出来ないので、その濃い影をアンビエントオクルージョンは担当します。例のごとくポストプロセスです。名前がかっこいいですね。
参考リンク
被写界深度 - Depth of Field: DoF
知っていた方がいい度:★★★☆☆
被写界深度(DoF)とは、今見ているもの以外の視界がぼやけて見える現象のことです。カメラで近くのものを撮影すると回りがぼやけて見えるのが分かりやすいかと思います。最近の洋ゲーとかの会話シーンとかだと会話している人たちはくっきりしていて壁など周りのものがぼやけて見えていることが多いですよね。
参考リンク
ブルーム - Bloom
知っていた方がいい度:★★★☆☆
ブルームとは、明るさが一定以上に達したところの周りがうっすら光って見える現象のことです。暗いところでろうそくを点けると赤い光がぼやーと見えますよね。あれです。この効果もゲームに適用すると見た目の印象が凄く変わります。似たような効果にフレアというものがあります。樹の下から太陽を見上げた時の星や十字の様に見える光の漏れみたいなやつです。ブルームもフレアもポストプロセスです。今回はブルームのみ紹介します。
参考リンク
モーションブラー - Motion Blur
知っていた方がいい度:★★★☆☆
モーションブラーとは、モノが大きく動く時に動く逆方向にブラー(ぼかし)をかけることで物体が高速で動いているように見せる手法の事です。電車に乗って近くのものが早すぎて残像しか見えない状態と全く同じです。モノがいかにも高速で動いているのを効果的に見せたい場合は必須のポストプロセスになります。
参考リンク
レイトレーシング - Ray Tracing
知っていた方がいい度:★★★★★
最近流行ってますね。レイトレーシングです。レイトレーシングを用いると、これまで紹介した手法より更に現実世界の見え方に限りなく近い結果を得る事ができます。例えば、近年の映画の現実と見分けがつかない様な表現は、ものすごく時間をかけたレイトレーシングの結果から算出しています。
レイトレーシングはこれまで紹介した手法とは根本から違います。従来のレンダリングはラスタライズと呼ばれる三角ポリゴンを座標変換し画面上のピクセルに落とし込む手法をとっていますが、レイトレーシングは視線から画面上の各ピクセル方向にレイ(光線)を飛ばし、光に照らされている物体に反射や屈折しながら複数回衝突ことで最終的な色を導き出します。つまり、オブジェクトとの当たり判定がレンダリング過程に存在しているすごいやつなんです。
更に、レイトレーシングが注目されている理由はこれまで紹介した表現技法(物理ベースレンダリング、シャドウ、大域照明、ポストプロセス等)がレイトレーシングのパスだけで完結してしまうという点です。幾度となくシェーダを走らせなくてもレイトレーシングだけで美麗な表現ができてしまうのがポイントです。
しかし、レイトレーシングには決定的な弱点があります。それは計算にとてつもなく時間がかかってしまうという点です。いくら美麗な表現ができても、リアルタイム性が求められるゲームでは高速で表示できなければ意味がありません。
そのため、謎の半導体メーカーや3Dグラフィクス関連の団体がリアルタイムで表示できる様にいろいろ頑張っているというのが現状です。
ちなみに、単純な形のジオメトリ(球体、立方体、トーラスなど)くらいは現状でもリアルタイムに表示することができます。レイトレで調べると球体が多いのはそのためです。
参考リンク
レイマーチング - Ray Marching
知っていた方がいい度:★★★☆☆
レイマーチングはレイトレーシングのレイの飛ばし方の一種で、光線追跡の中では一般的な手法です。レイマーチングによりグラフィクス処理専門のGPUでもオブジェクトとの当たり判定を実現することができます。
簡単に説明すると、レイの現在位置から一番近いオブジェクトとの距離を計算し、その距離分だけレイが向いている方向に進める事を繰り返し、最終的にレイの位置から一番近いオブジェクトとの距離が閾値以下となったらオブジェクトと衝突したと判定します。
衝突した位置のサーフェイスの色を出力できれば、基本的なレイマーチングができたと言えるでしょう。
参考リンク
パストレーシング - Path Tracing
知っていた方がいい度:★★★☆☆
パストレーシングはレイトレーシングの一種で、複数のレイをオブジェクトの拡散反射・鏡面反射の積分範囲内でモンテカルロ法を使って統計的サンプリングを行いその平均値を推定し色を算出する手法です。ざっくりいうと、レイが当たった場所からランダムにレイを複数飛ばして平均値を求める改良型レイトレーシングです。本来反射の積分範囲内はすべて計算しなければ奇麗な結果になりませんが、いい感じの場所をサンプリングする事で高速化するのが特徴です。モンテカルロ法を用いることからモンテカルロレイトレーシングとも呼ばれたりします。
ランダムにレイを飛ばすためノイズが乗りますが、時間をかけて平均化させると実写と見間違うきれいな結果になります。ただ、ノイズが乗りがち+結果を得るまで時間がかかるという問題があるので、改良の余地はまだまだあると考えられます。
参考リンク
まとめ
如何でしたでしょうか。
「最近の3Dはこんなことやってるのか~」と思っていただければ幸いです。
もちろん、今回紹介したもの以外にも多数の手法が3DCG界隈には存在しています。その中でも、特に知っていて欲しいものをピックアップしました。
今回紹介したもの以外にもこれは重要だから紹介してほしいというものがあったらコメントください。暇ができた時追記します。
良き3Dプログラミングライフを。