SSAO随摄像机角度发生剧烈变化

时间:2013-07-15 05:19:08

标签: opengl glsl deferred-rendering ssao

我一直在OpenGL中工作SSAO。我决定从OpenGL的this教程中为我的延迟渲染器实现SSAO。不幸的是,我一直无法让它运作良好。 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()函数中,除了我在渲染器的照明阶段使用相同的代码(我认为)。我已经对这段代码进行了一千次的处理,并没有找到任何突出的错误。我为biasradiusintenistyscale尝试了各种值,但这似乎不是问题。我担心我的法线或位置是错误的,所以这里有一些屏幕截图:

重建位置: enter image description here 和正常的缓冲区: enter image description here

我会包含遮挡缓冲区的图像,但问题主要是在相机移动时才会显而易见,图像无法显示。

有没有人知道这里有什么问题?

1 个答案:

答案 0 :(得分:3)

奇怪的是,乘以2并减去1对你的法线贴图没有帮助。通常这样做是为了克服与以无符号/标准化纹理格式存储法线相关的问题。除非您的普通G-Buffer是有符号/非标准化格式,否则您可能需要在第一次写入时使用* 0.5 + 0.5打包并解压缩法线,并在对纹理进行采样时使用* 2.0 - 1.0

在任何情况下,SSAO都有多种方法,许多方法甚至根本不使用表面法线。因此,关于存储法线的向量空间的讨论经常被忽略。

我强烈怀疑你的法线是在视野中,而不是世界空间。如果您将法线乘以顶点着色器中的“普通矩阵”,就像许多教程一样,那么法线将位于视图空间中。

事实证明,视图空间法线实际上并没有那么有用,现在使用世界空间法线可以更好地处理后处理效果。大多数现代延迟着色引擎(例如虚幻引擎4,CryEngine 3等)将普通G-Buffer存储在世界空间中,然后将其转换为像素着色器中的视图空间(如果需要)。


顺便说一句,我已经包含了一些代码,用于从传统的深度缓冲区重建对象空间位置。您似乎正在使用视图空间位置/法线。您可能想要尝试对象/世界空间中的所有内容。

flat in mat4 inv_mv_mat;
     in vec2 uv;

...

float linearZ (float z)
{
#ifdef INVERT_NEAR_FAR
  const float f = 2.5;
  const float n = 25000.0;
#else
  const float f = 25000.0;
  const float n = 2.5;
#endif

  return n / (f - z * (f - n)) * f;
}

vec4
reconstruct_pos (in float depth)
{
  depth = linearZ (depth);

  vec4 pos = vec4 (uv * depth, -depth, 1.0); 
  vec4 ret = (inv_mv_mat * pos);

  return ret / ret.w;
}

在延迟着色光照过程的顶点着色器阶段需要一些额外的设置,如下所示:

#version 150 core

in       vec4 vtx_pos;
in       vec2 vtx_st;

uniform  mat4 modelview_mat; // Matrix used when the G-Buffer was built
uniform  mat4 camera_matrix; // Matrix used to stretch the G-Buffer over the viewport

uniform float buffer_res_x;
uniform float buffer_res_y;

     out vec2 tex_st;
flat out mat4 inv_mv_mat;
     out vec2 uv;


// Hard-Coded 45 degree FOV
//const float fovy = 0.78539818525314331; // NV pukes on the line below!
//const float fovy = radians (45.0);
//const float tan_half_fovy = tan (fovy * 0.5);

const float   tan_half_fovy = 0.41421356797218323;

      float   aspect        = buffer_res_x / buffer_res_y;
      vec2    inv_focal_len = vec2 (tan_half_fovy * aspect,
                                    tan_half_fovy);

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


void main (void)
{
  inv_mv_mat  = inverse (modelview_mat);
  tex_st      = vtx_st;
  gl_Position = camera_matrix * vtx_pos;
  uv          = (vtx_st * uv_scale - uv_translate) * inv_focal_len;
}