(中国語の詳しい説明) smallpt: 99 行のコードでグローバル イルミネーション パス トレースを完了する

0.SmallPTとは

ここに画像の説明を挿入します

smallpt は、グローバル イルミネーション レンダラです。そのコア コードは 99 行の C++ コードで構成されています。上のシーンは、不偏モンテカルロ パス トレーシング (不偏モンテカルロ パス トレーシング アルゴリズム) を使用してレンダリングされます。

このブログの目的は、smallPT の原理とコード対応の意味を紹介することです (主にオクラホマ州立大学の David Cline 教授の ppt を参考にします) この記事を通じて、読者の皆様にレイ トレーシングのアルゴリズムを理解していただければ幸いです。コード レベル: パス トレース、レンダリング プロセス全体を明確に理解します。

特徴

  • 不偏モンテカルロ パス トレーシングに基づくグローバル イルミネーション (オープン ソース C++ コード)
  • OpenMPを使用したマルチスレッドアクセラレーション
  • 拡散照明を使用してソフト シャドウを生成します (ソフト シャドウ)
  • 鏡面反射光、拡散反射光、ガラス BRDF (レンダリング パイプラインのマテリアル プロパティ)
  • 重要度サンプリングに基づくスーパーサンプリングのアンチエイリアシング方法
  • 光線と球の交差
  • 拡散反射のための半球のコサイン重要度サンプリング
  • ロシアンルーレット(ライトストップ用)

1. レイ トレーシングには知識が必要です

1.1 グローバルイルミネーションとは何ですか?

グローバル イルミネーションは、シーン上で仮想写真操作を実行することと同等です。

ここに画像の説明を挿入します

下の写真はアドホック ライティングとグローバル イルミネーションでレンダリングした画像の違いで、グローバル イルミネーションの方がドラゴンが明るく、前後の影がより調和していることがわかります
ここに画像の説明を挿入します
では、グローバル イルミネーションのレンダリング結果を取得するにはどうすればよいでしょうか?
その答えは「リバースエンジニアリング」です。つまり、レンダリングされた画像の各ピクセル位置からレンズに光を放射し、一連の屈折と反射に従って最終的に光源上の点に到達します。これをレイトレーシングといいます(代表的なものはパストレーシングです)。
ここに画像の説明を挿入します

1.2 レンダリング方程式

レンダリング方程式とは何ですか? レンダリング方程式は、1986 年に長髪のジム カディアによって発明されました。それ以来、この方程式は、映画、テレビ、アニメーション、ゲーム、視覚効果、その他の業界のあらゆる側面に直接影響を与えてきました。
ここに画像の説明を挿入します

以下は、点光源のみを考慮する (光の反射は考慮しない) レンダリング方程式の例です。その場合、レンダリング方程式は非常に単純です。その中で、
ここに画像の説明を挿入します
L ( x → wr ) L(x \rightarrow w_r) は次のようになります。方程式の左辺L ( ×wr)は、表面上の点 x からwr w_rwr半径、これが計算したいものです。方程式の右辺は、マテリアルの自己照明項 (周囲光または放射) と入射光とマテリアルの入射面積 (BRDF) です。

しかし、相互反射の場合、レンダリング方程式を解くのは困難です...各表面から反射される放射輝度が明確ではないため、どのように調整すればよいでしょうか? まず、後続の操作を容易にするためにレンダリング方程式を省略します (u
ここに画像の説明を挿入します
発信vはインシデント、赤は不明を意味します):

I(u) = e(u) + f I(v) K(u,v)dv
ここに画像の説明を挿入します

これはまだ十分に単純化されていません。最初に u と v を省略してから、赤いボックスの内容 (単純な行列方程式) に単純化します。L が再帰的であることがわかり
ここに画像の説明を挿入します
、L に基づいて解析解を求めます。テイラー級数展開に従って、L の形式がわかることがわかります。ここに画像の説明を挿入します
この形式によれば、代入は簡単です。物理的意味:つまり、どの項目が自己照明を表し、どの項目が擬似光源のバウンス数(光が何回跳ね返るか)を表しており、反射も間接照明であることがわかります

ここに画像の説明を挿入します
, Lao Yan が紹介しました: ラスタライズを直接実行できるのは E と KE だけです。
つまり、ラスタライズでは間接照明の効果を簡単にシミュレートできません。これは非常に悲痛です...

したがって、より要求の厳しいエフェクトについては、引き続きレイ トレーシングを使用します。これが、この記事のグローバル イルミネーションにつながります~

さて、それは少し言いすぎたので、この記事で焦点を当てているパス トレーシングの論理プロセスに戻ります。私たちの物語では、引き続きこの図を例として使用します。プロセスは次のとおりです
ここに画像の説明を挿入します

  • ① 色を計算するピクセルごとに、samplesPerPixel のサンプリング ポイントを設定します (この値が大きいほどレンダリング効果は向上しますが、速度は遅くなります)。
  • ②レンズ上の点P レンズ P_{lens}をランダムに選択しますPレンズ_ _ _画像平面上の点 P と画像 P_{image}P_ _ _、光線を構築します (レンズ上のランダムな点を原点として開始し、方向は正規化されます( P image P_{image}P_ _ _- P レンズ P_{レンズ}Pレンズ_ _ _)。
  • ③ 光線を放射し、光線がオブジェクト (上図の散乱点など) に直接触れた場合、その散乱点を新しい光線の開始点として使用し、元の位置に戻るまで新しい光線を構築し続けます。光源上の点。オブジェクトとの接触がない場合は、背景色が使用されます。
  • ④ 最後に、C を各ピクセルのサンプリング ポイント (平均) で除算して、対応するピクセルのレンダリング結果を取得します。
    ここに画像の説明を挿入します

2. SmallPT コード分析

元のコードは Kevin Beason によって書かれた 99 行のコードですが、簡潔すぎて理解しにくいという不満の声が多くありました。そこで、オクラホマ州立大学の David Cline 教授は、オブジェクト指向 (OOP) アプローチを使用して、これを 218 行に拡張し、主要な部分を列挙して、読みやすいバージョンの SmallPT を完成させました。
ここに画像の説明を挿入します

2.1 コードブロック 1

その役割は、Vec、Ray、Sphere (smallPT には球のレンダリングのみが含まれます) などの一般的に使用される構造、およびいくつかの関数関数と球の初期化を含めることです。
ここに画像の説明を挿入します
球の初期化ステップから、渡された 5 つのパラメーターが順序どおりであることがわかります。

  • ①球半径(半径):1e5、16.5、600があります。
  • ② 球の位置: レンダリング結果の 2 つの球の対応する半径は 16.5 であり、位置はそれぞれ Vec(27, 16.5, 47) と Vec(73, 16.5, 78) になります。
  • ③ 発光: デフォルトでは、すべて空です。つまり、環境光項目はすべて 0 です。
  • ④色:球の色です。
  • ⑤マテリアル:DIFF、SPEC、REFRの計3種類あります。

ここに画像の説明を挿入します

Vec 構造の詳細な紹介。その目的は、POINTS、COLORS、および VECTORS の基本構造を提供することです。

Norm() の意味は光線の方向を見つけること、内積は余弦角を見つけること、外積は正弦角を見つけることです。
ここに画像の説明を挿入します
ここに画像の説明を挿入します
ここに画像の説明を挿入します
光線の構造を以下に紹介します。その形式は次のとおりです: P (t) = O + t DP(t) = O + tDP ( t )=+
ここに画像の説明を挿入します
以下のt Dは球の構造です。球の中心と半径によって球を定義できます。その方程式とベクトルの形式は以下に与えられます。
ここに画像の説明を挿入します
球と光線の交差を判断するための解析解形式:
ここに画像の説明を挿入します
交差を判断するためのコードは次のとおりです。

  • double b = op.dot(rd) は、b = 2 D ⋅ ( O − C ) b = 2D · (O - C)に対応します。b=2D⋅ _ _( OC )DDDはコード内の rd、OOOは光線の源ですro、CCCの球の中心 p 。したがって、b は 0.5b になります。

  • det = ( b 2 − 4 ac ) 4 \frac{(b^2 - 4ac)}{4}4( b24ac)なぜなら、 a = ( D ⋅ D ) (D · D)( D D )、その係数は 1 であるため、a=1. det =b 2 − cb^2 - cb2c

  • 最後に、光線と交差する最も近い平面上の点を表す、最小の正の t が返されます。
    ここに画像の説明を挿入します
    シーン グラフは次のようになります。正しくレンダリングされれば、次の結果が得られるはずです。
    ここに画像の説明を挿入します

2.2 コードブロック 2

その機能は、半径を計算し、main 関数を実行することです。
このうち、メイン関数の機能には、カメラ位置の設定、ピクセルごとのスーパーサンプリング アンチエイリアシング、並列命令などが含まれます。

ここに画像の説明を挿入します
ここに画像の説明を挿入します

2.2.1 メイン機能ステップ 1: イメージ プレーンを設定する

ここでは、レンダリングされたイメージを表示するために、高さ 384、幅 512 のイメージ プレーンが構築されていることがわかります。明らかに、画像が小さいほど、レンダリングの計算コストが小さくなり、計算が速くなります。
ここに画像の説明を挿入します

2.2.2 メイン機能ステップ 2: カメラ位置の設定

カメラの位置と方向は非常に重要で、設定を誤ると、完全に黒くなったり、部分的に見えたりする可能性があります。ここに画像の説明を挿入します
カメラの設定には、カム(カメラの位置と方向)、カメラの水平方向、垂直方向が含まれます。0.5135 は視野角を表します。

ここに画像の説明を挿入します
ここに画像の説明を挿入します

2.2.3 メイン機能ステップ 3: イメージの作成

このステップは実際には以前のパス トレース擬似コードの具体的な実装ですが、擬似コード バージョンと比較して、このバージョンではスーパーサンプリング アンチエイリアス(アンチエイリアシング) とテント フィルター(シャドウ マップ)が追加されています。
ここに画像の説明を挿入します
for ループを並列に実行することです。各ピクセルのレンダリングは互いに干渉しないため、OpenMP を並列加速に使用できます。
ここに画像の説明を挿入します
② イメージ プレーン上のすべてのピクセルを走査します
ここに画像の説明を挿入します
。 ③ サブピクセル、アンチエイリアシングに使用します。 c[i] = c[i] + Vec(…) * 0.25, 0.25~ に注意してください。
ここに画像の説明を挿入します

④ピクセルインデックス

ピクセル i のインデックス位置を計算します。i = ( h − y − 1 ) ∗ w + xi = (hy-1) * w + x である理由に注意してください。=( hy1 )w+xはどこですか?これは、OPENGL デバイス座標系が左手系の座標系、画面座標系の原点が左下隅、右上に向かって増加するためです。
ここに画像の説明を挿入します

⑤ テントフィルター

テントフィルターとは何ですか?誰かが「とてもいいですね~」と尋ねましたが[3]、Nvidia の上司である Nathan Reed は次のように答えました。

sinc filter波形図
ここに画像の説明を挿入します

理論的には、最良のアンチエイリアシング方法は sinc フィルターです[4]。sinc フィルターはナイキスト周波数よりも高い周波数をすべて完全に除去し、低い周波数を保持できるため、私たちの目標は、sinc フィルターの波形に可能な限り近づけることです。完璧を達成するにはアンチエイリアシング効果。
ここに画像の説明を挿入します
smallPT がテント フィルターを使用する理由について、ネイサン兄弟は次のように考えています。テント フィルターはコードが少なく、数行で実行できるのに対し、バイキュービック フィルターは複数行のコードが必要です。
ここに画像の説明を挿入します
ここに画像の説明を挿入します
⑥ cam.d、cx、cy を使用して光の方向を計算し、放射輝度を計算し、サブピクセル推定値を合計します。

ここに画像の説明を挿入します
ここに画像の説明を挿入します

2.2.4 半径を計算するにはどうすればよいですか?

①交点判定を行い、交点がなければそのまま戻り、交点があれば最も近い交点の球objを取り出す。

ここに画像の説明を挿入します
変数 Xi は、乱数 (erand48() によって生成される) を格納するために使用され、行番号の任意の関数を使用してシードされ、行から行へのシーケンスを (少なくとも視覚的に) 非相関化します。

② 表面法線、色(BRDF変調器)等の情報を取得する

ここに画像の説明を挿入します
nl の方向に注意してください。ガラス表面の場合、レイ トレーサはガラスに入るのかガラスから出るのかを判断し、これを使用して屈折光線を計算する必要があります。私の理解では、法線の方向は光線の方向に基づいて決定する必要があり、これは特定のマテリアル (ガラス) のオブジェクト レンダリングにとって非常に重要です。
ここに画像の説明を挿入します

③ロシアンルーレット:再帰的な輝度計算を終了するために使用します
ここに画像の説明を挿入します

2.3 shading 着色

2.3.1 拡散反射 拡散反射

ここに画像の説明を挿入します

ここでは、角度 r1 と中心からの距離 r2 をランダムに計算して直交座標 (w、u、v) を計算し、
ここに画像の説明を挿入します
ここに画像の説明を挿入します
表面の拡散反射 (光の跳ね返り) を計算します。現実世界では、オブジェクトは必ずしも光源によって照らされているわけではありませんが、他のオブジェクトが発する光の影響も受けます。具体的な計算式はここでは説明しません。助けが必要なお子様には、Unity シェーダーを読むことをお勧めします。フォン・レレ先生が書いた本。
ここに画像の説明を挿入します

2.3.2 理想的な鏡面反射

ここで使用されるのは、最も単純な理想的な鏡面反射、つまり、入射角 == 出射角です。
ここに画像の説明を挿入します

2.3.3 ガラス材質(誘電体)

ここに画像の説明を挿入します
ここで David Cline 教授がこのコードを分析しています。まず第一に、ガラス自体は反射性屈折性の両方を持つことができるため、ここでの計算は反射光です。why?

ガラスの場合は nt を 1.5 に設定し、nnt を 1.5 または 1/1.5 に設定します
(nt または nnt とは何ですか? 次の内容で説明します。1.5はガラスの屈折率です~ )

ここに画像の説明を挿入します
異常な状況が発生すると、たとえば、光線がガラスから出ようとするが、出射角が小さすぎる(角度が浅い)場合、すべての光が反射されます。
ここに画像の説明を挿入します
フレネル項を使用して屈折光を計算します。
ここに画像の説明を挿入します

T は屈折光の方向です。
ここに画像の説明を挿入します
フレネル項とは何ですか?

は入射角 ( θ a \theta_a) は、ガラス表面からの光の反射/屈折の割合です。

法線入射方向の反射率はF o = ( n − 1 ) 2 ( n + 1 ) 2 F_o = \frac{(n-1)^2}{(n+1)^2} です。Fああ=( n + 1 )2( n 1 )2、他の角度での反射はF r ( θ ) = F o + ( 1 − F o ) ( 1 − cos ⁡ θ ) 5 F_r(\theta) = F_o + (1 - F_o)(1 - \cos\ theta )^5Fr()=Fああ+( 1Fああ) ( 1コス5

ここに画像の説明を挿入します
ここに画像の説明を挿入します

4. レンダリング効果

上記の各項目の意味は十分に説明されていません。必要な学生は、それでも一行ずつデバッグする必要があります。[1, 2]ピクセルあたりのサンプル数が増加するにつれて、パス トレースの効果が向上することがわかります。明らかに、レンダリング効率が向上します。もかなり低くなりました〜
ここに画像の説明を挿入します

参考文献

  1. David Cline 教授が smallPT のスライドを紹介
  2. smallPT – ケビン・ビーソン
  3. パス トレースでテント フィルターを使用する理由 — スタック交換
  4. シンクフィルター

おすすめ

転載: blog.csdn.net/g11d111/article/details/108189198