位置再構築
これが有効な方法であり、何かを見落としていないことを確認したい。
光が重なる画面の部分のみをレンダリングするために使用している球状メッシュを使用しています。ここで提案されているように、深度が深度バッファー以上の場合、背面のみをレンダリングします。
フラグメントのカメラ空間位置を再構築するために、ライト ボリュームのカメラ空間フラグメントからベクトルを取得し、それを正規化し、gbuffer ( 32 ビット floatとして格納されている) から線形深度でスケーリングしています。これは、ここで説明した方法(線形深度を使用)とここ (球状のライト ボリューム)のハイブリッドのようなものです。
バンディング
私が質問する理由は、光の減衰について遅延と順方向から得られる結果が異なるためです。
据え置き
前方
次のように減衰を計算すると、減衰はカメラ空間の位置にリンクされます。
vec3 light_dir_to = curr_light.camera_space_position - surface_pos_cam;
float light_dist_sq = dot(light_dir_to, light_dir_to);
float light_attenuation_factor = 1.0f - ((1.0f / (curr_light.radius * curr_light.radius)) * light_dist_sq);
light_attenuation_factor = clamp(light_attenuation_factor, 0.0f, 1.0f);
light_attenuation_factor = pow(light_attenuation_factor, curr_light.falloff);
これらの例では、違いはあまり目立ちませんが、ライトをスケーリングしようとすると (たとえば、フェードアウトを速くするためにパワーを上げます)、効果がすぐに明らかになります。
light_atten = pow(light_atten, 2.0f)
私の問題は別の場所にあるかもしれませんが、私の位置再構築方法に見落としているような欠陥がないことを確認したいと思います。
編集
要求に応じて gbuffer セットアップを投稿します。
enum render_targets { e_dist_32f = 0, e_diffuse_rgb8, e_norm_xyz10, e_spec_intens_b8_spec_pow_a8, e_light_rgb8, num_rt };
//...
GLint internal_formats[num_rt] = { GL_R32F, GL_RGBA8, GL_RGB10_A2, GL_RGBA8, GL_RGBA8 };
GLint formats[num_rt] = { GL_RED, GL_RGBA, GL_RGBA, GL_RGBA, GL_RGBA };
GLint types[num_rt] = { GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT };
for(uint i = 0; i < num_rt; ++i)
{
glBindTexture(GL_TEXTURE_2D, _render_targets[i]);
glTexImage2D(GL_TEXTURE_2D, 0, internal_formats[i], _width, _height, 0, formats[i], types[i], nullptr);
}
// Separate non-linear depth buffer used for depth testing
glBindTexture(GL_TEXTURE_2D, _depth_tex_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, _width, _height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
注:この問題は、サーフェス全体に対して 1 つの法線を持つ平面サーフェスで発生するため、法線の精度が失われることはありません。
最終編集 - 解決策
このメソッドは実際に有効であるかのように見えます (GuyRT が述べているように)。バンディングの問題は、ガンマ補正のやり方に起因しているようです。
私のフォワード レンダラーでは、8 つのライトに対して 1 つのループしかなく (複数のパスは実行せず、1 つのパスのみ)、照明計算の直後にガンマ補正を適用します。
私のディファード レンダラーでは、すべての照明計算、後処理などを行ってから、ガンマに変換します。ここでの問題は、次のことです。
- 線形 RGB 空間で照明計算を行う
- RGB 空間のテクスチャに格納します(精度は 8 ビットのみ)。
- ライティングが完了したら、値をガンマ補正し、バック バッファーにコピーします。
たとえば、2 つのフラグメントのライティング計算の最終値が sRGB 空間で 1/255 (~0.003) と 2/255 (~0.007) であるとします (最後に示されています)。RGB 空間でのこれらの値は、(1/255)^2.2 = ~0.000006 および (2/255)^2.2 = ~0.00002 です。これらの値がライティング アキュムレート テクスチャに保存されると、両方とも同じ値 0 として保存されます。これがバンディングの原因です。
ライティング アキュムレーション テクスチャをGL_R11F_G11F_B10Fに変換すると、フォワード レンダラーに非常に近い結果が得られました。ガンマが問題であることがわかったとき、これら 2 つの質問に対する答えが役に立ちました: sRGB テクスチャです。これは正しいです?glEnable(GL_FRAMEBUFFER_SRGB) をいつ呼び出すか? .
「フォールオフ」が 4.0 の最終結果
追加のリソース
この効果が「ガンマ バンディング」と呼ばれていることを知りました。このWeb サイトにはいくつかの便利なチャートがあり、このビデオにはすばらしい数値ウォークスルーがあります。