1

私はOpenGLでSSAOに取り組んできました。このチュートリアルのSSAO をOpenGL で遅延レンダラーに実装することにしました。残念ながら、私はそれをうまく機能させることができませんでした。SSAOで暗くなる部分は、カメラの位置によって大きく変化します。カメラが動いたときに SSAO の出力に多少の変動があることは理解していますが、これは SSAO の他の実装で観察したよりもはるかに大きいです。

これがフラグメントシェーダーコードです

void main() {

    vec3 origin = positionFromDepth(texture2D(gDepth, samplePosition));
    vec3 normal = texture2D(gNormal, samplePosition).xyz; //multiplying this 
//by 2 and subtracting 1 doesn't seem to help
    vec2 random = getRandom(samplePosition);

    float radius = uRadius/origin.z;
    float occlusion = 0.0;
    int iterations = samples/4;

    for (int i = 0; i<iterations; i++) {
        vec2 coord1 = reflect(kernel[i], random)*radius;
        vec2 coord2 = vec2(coord1.x*0.707 - coord1.y*0.707, coord1.x*0.707 + coord1.y*0.707);
        occlusion += occlude(samplePosition, coord1 * 0.25, origin, normal);
        occlusion += occlude(samplePosition, coord2 * 0.50, origin, normal);
        occlusion += occlude(samplePosition, coord1 * 0.75, origin, normal);
        occlusion += occlude(samplePosition, coord2, origin, normal);
    }

    color = vec4(origin, 1);

}

positionFromDepth()機能:

vec3 positionFromDepth(float depth) {
    float near = frustrumData.x;
    float far = frustrumData.y;
    float right = frustrumData.z;
    float top = frustrumData.w;
    vec2 ndc;           
    vec3 eye;             
    eye.z = near * far / ((depth * (far - near)) - far);
    ndc.x = ((gl_FragCoord.x/buffersize.x) - 0.5) * 2.0; 
    ndc.y = ((gl_FragCoord.y/buffersize.y) - 0.5) * 2.0;
    eye.x = (-ndc.x * eye.z) * right/near;
    eye.y = (-ndc.y * eye.z) * top/near;
    return eye;
}

そしてocclude()機能:

float occlude(vec2 uv, vec2 offsetUV, vec3 origin, vec3 normal) {
    vec3 diff = positionFromDepth(texture2D(gDepth,(uv+offsetUV)))-origin;
    vec3 vec = normalize(diff);
    float dist = length(diff)/scale;
    return max(0.0,dot(normal,vec)-bias)*(1.0/(1.0+dist))*intensity;
}

positionFromDepth()完全に機能するレンダラーの照明ステージに同じコードを使用することを除いて、関数に問題がある可能性があると感じています(私は思います)。私はこのコードを何千回も調べましたが、間違っていると思われるものは何も見つかりませんでした。biasradiusintenisty、のさまざまな値を試しましたscaleが、問題はないようです。法線または位置が間違っているのではないかと心配しているので、それらのスクリーン ショットをいくつか示します。

再構築された位置: ここに画像の説明を入力 通常のバッファ: ここに画像の説明を入力

私はオクルージョン バッファの画像を含めますが、問題はカメラが動いている場合にのみ明らかになり、画像は表示に役立ちません。

ここで何が問題なのか誰にもわかりませんか?

4

1 に答える 1

3

2 を掛けて 1 を引いても法線マップが役に立たないのは奇妙です。これは通常、法線を署名なし/正規化されたテクスチャ形式で保存することに関連する問題を解決するために行われます。通常の G-Buffer が符号付き/正規化されていない形式でない限り、* 0.5 + 0.5最初に書き込む* 2.0 - 1.0ときとテクスチャをサンプリングするときに使用して、おそらく法線をパックおよびアンパックする必要があります。

いずれにせよ、SSAO には複数のアプローチがあり、その多くはサーフェス法線をまったく使用しません。そのため、法線をどのベクトル空間に格納するかについての議論は見過ごされがちです。

あなたの法線は、ワールド空間ではなくビュー空間にあると強く思います。多くのチュートリアルで行うように、頂点シェーダーで法線を「法線マトリックス」で乗算すると、法線はビュー空間になります。

ビュー スペースの法線は、実際にはそれほど有用ではないことが判明しました。最近では、ワールド スペースの法線を使用した方が適切に機能する後処理エフェクトが多数あります。最新のディファード シェーディング エンジン (Unreal Engine 4、CryEngine 3 など) のほとんどは、通常の G バッファーをワールド空間に格納し、ピクセル シェーダーで (必要に応じて) ビュー空間に変換します。


ところで、従来の深度バッファーからオブジェクト空間の位置を再構築するために使用するコードをいくつか含めました。ビュー空間の位置/法線を使用しているようです。オブジェクト/ワールド空間ですべてを試してみることをお勧めします。

mat4 inv_mv_mat でフラット。
     vec2 uv;

...

float linearZ (フロート z)
{
#ifdef INVERT_NEAR_FAR
  const float f = 2.5;
  const float n = 25000.0;
#そうしないと
  const float f = 25000.0;
  const float n = 2.5;
#endif

  n / (f - z * (f - n)) * f; を返します。
}

vec4
rebuild_pos (フロートの深さ)
{
  深さ = linearZ (深さ);

  vec4 pos = vec4 (uv * 深さ、-深さ、1.0);
  vec4 ret = (inv_mv_mat * pos);

  戻ります ret / ret.w;
}

次のように、ディファード シェーディング ライティング パスの頂点シェーダー ステージで少し追加のセットアップが必要です。

#バージョン 150 コア

vec4 で vtx_pos;
vec2 vtx_st で。

均一なmat4モデルview_mat; // G-Buffer が構築されたときに使用される行列
均一な mat4 camera_matrix; // ビューポート上で G-Buffer をストレッチするために使用されるマトリックス

均一なフロート buffer_res_x;
均一なフロート buffer_res_y;

     vec2 tex_st; を出力します。
平らにします mat4 inv_mv_mat;
     vec2 uv;


// ハードコーディングされた 45 度 FOV
//const float fovy = 0.78539818525314331; // 下の行で NV pukes!
//const float fovy = radians (45.0);
//const float tan_half_fovy = tan (fovy * 0.5);

const float tan_half_fovy = 0.41421356797218323;

      float アスペクト = buffer_res_x / buffer_res_y;
      vec2 inv_focal_len = vec2 (tan_half_fovy * アスペクト、
                                    tan_half_fovy);

const vec2 uv_scale = vec2 (2.0, 2.0);
const vec2 uv_translate = vec2 (1.0, 1.0);


ボイドメイン(ボイド)
{
  inv_mv_mat = 逆 (modelview_mat);
  tex_st = vtx_st;
  gl_Position = camera_matrix * vtx_pos;
  uv = (vtx_st * uv_scale - uv_translate) * inv_focal_len;
}
于 2013-07-17T17:20:43.077 に答える