GLSL - SSAO:获取深度位置时获得不需要的结果

时间:2014-05-11 01:42:53

标签: c++ opengl glsl post-processing ssao

我正在尝试根据本教程实施SSAO:http://john-chapman-graphics.blogspot.com/2013/01/ssao-tutorial.html。我似乎不明白如何实现这一点,并且我在片段着色器中不断得到不希望的结果。

首先我设置我的着色器以传递深度缓冲区,相机的投影矩阵和4x4噪声纹理。 ssao内核已经初始化并传递到着色器中。我还从深度缓冲区中采样法线。

编辑:起初我以为我的深度位置不正确,所以我添加了一个名为positionFromDepth的新功能,但它似乎仍无法正常工作......

我的片段着色器:

uniform sampler2D uDepthBuffer;
uniform sampler2D uNoiseTexture;

uniform mat4 uProjection; // camera's projection matrix
uniform mat4 uInverseMatrix; // inverse of projection matrix
uniform vec2 uNoiseScale; // vec2(1024.0 / 4.0, 768.0 / 4.0)

const int MAX_KERNEL_SIZE = 128;

uniform int uSampleKernelSize;
uniform vec3 uSampleKernel[MAX_KERNEL_SIZE];

uniform float uRadius;

const float zNear = 0.1;
const float zFar = 2579.5671;

float linearizeDepth(float near, float far, float depth) {
    return 2.0 * near / (far + near - depth * (far - near));
}

vec3 positionFromDepth(vec2 texcoords) {
    float d = linearizeDepth(zNear, zFar, texture2D(uDepthBuffer, texcoords).r);
    vec4 pos = uInverseMatrix * vec4(texcoords.x * 2.0 - 1.0,
                                     texcoords.y * 2.0 - 1.0,
                                     d * 2.0 - 1.0, 1.0);

    pos.xyz /= pos.w;

    return pos.xyz;
}

vec3 normal_from_depth(float depth, vec2 texcoords) {
  const vec2 offset1 = vec2(0.0, 0.001);
  const vec2 offset2 = vec2(0.001, 0.0);

  float depth1 = linearizeDepth(zNear, zFar, texture2D(uDepthBuffer, texcoords + offset1).r);
  float depth2 = linearizeDepth(zNear, zFar, texture2D(uDepthBuffer, texcoords + offset2).r);

  vec3 p1 = vec3(offset1, depth1 - depth);
  vec3 p2 = vec3(offset2, depth2 - depth);

  vec3 normal = cross(p1, p2);
  normal.z = -normal.z;

  return normalize(normal);
}

void main() {
    vec2 texcoord = gl_TexCoord[0].st;

    vec3 origin = positionFromDepth(texcoord);

    float d = texture2D(uDepthBuffer, texcoord).r;
    vec3 normal = normal_from_depth(linearizeDepth(zNear, zFar, d), texcoord) * 2.0 - 1.0;
    normal = normalize(normal);

    vec3 rvec = texture2D(uNoiseTexture, texcoord * uNoiseScale).rgb * 2.0 - 1.0;
    vec3 tangent = normalize(rvec - normal * dot(rvec, normal));
    vec3 bitangent = cross(normal, tangent);
    mat3 tbn = mat3(tangent, bitangent, normal);

    float occlusion = 0.0;

    for(int i = 0; i < uSampleKernelSize; i++) {
        vec3 sample = tbn * uSampleKernel[i];
        sample = sample * uRadius + origin.xyz;

        vec4 offset = vec4(sample, 1.0);
        offset = uProjection * offset;
        offset.xy /= offset.w;
        offset.xy = offset.xy * 0.5 + 0.5;

        float sampleDepth = positionFromDepth(offset.xy).z;
        occlusion += (sampleDepth <= sample.z ? 1.0 : 0.0);
    }

    occlusion = 1.0 - (occlusion / float(uSampleKernelSize));
    gl_FragColor = vec4(pow(occlusion, 4.0));
}

当我移动相机时,被遮挡的样本会发生变化。结果看起来像这样:

Result from SSAO shader

我假设我在采样深度位置时做错了,但也许我对投影矩阵做错了。 uProjection矩阵应该转置还是反转?任何人都可以识别这个问题吗?

还要忽略我尚未完成模糊传递的事实。

1 个答案:

答案 0 :(得分:0)

这里要考虑几件事。你已经用不同的东西替换了原来的linearizeDepth等式。原始linearizeDepth函数基于此formula

请注意,如果您尝试基于此公式派生函数,您将看到它实际上是Z的倒数,linearizeDepth函数不仅返回Z.

我不能说这会影响SSAO算法的程度,但鉴于我自己研究代码所学到的东西,我会非常小心地修补我不完全理解的等式部分。从本质上讲,我不确定代码是否应该更长时间。

具体来说,我认为在这种情况下linearizeDepth的目的不是在z轴上均匀分布光明和黑暗(我相信,这就是你在这里做的事情),而是相当便宜地取消Z项目'坐标。