SSAO实施未获得理想的结果


12

在实现了延迟渲染之后,我通过本教程尝试了SSAO实现。不幸的是,我没有得到任何看起来像SSAO的东西,您可以在下面看到我的结果。

不合格的骚骚

您会看到有一些奇怪的图案形成,并且在需要的地方(即在物体之间和地面上)没有遮挡阴影。我实现的着色器如下:


#VS
#version 330 core

uniform mat4 invProjMatrix;

layout(location = 0) in vec3 in_Position;
layout(location = 2) in vec2 in_TexCoord;

noperspective out vec2 pass_TexCoord;
smooth out vec3 viewRay;

void main(void){
    pass_TexCoord = in_TexCoord;
    viewRay = (invProjMatrix * vec4(in_Position, 1.0)).xyz;
    gl_Position = vec4(in_Position, 1.0);
}

#FS
#version 330 core

uniform sampler2D DepthMap;
uniform sampler2D NormalMap;
uniform sampler2D noise;

uniform vec2 projAB;
uniform ivec3 noiseScale_kernelSize;
uniform vec3 kernel[16];
uniform float RADIUS;
uniform mat4 projectionMatrix;

noperspective in vec2 pass_TexCoord;
smooth in vec3 viewRay;

layout(location = 0) out float out_AO;

vec3 CalcPosition(void){
    float depth = texture(DepthMap, pass_TexCoord).r;
    float linearDepth = projAB.y / (depth - projAB.x);
    vec3 ray = normalize(viewRay);
    ray = ray / ray.z;
    return linearDepth * ray;
}

mat3 CalcRMatrix(vec3 normal, vec2 texcoord){
    ivec2 noiseScale = noiseScale_kernelSize.xy;
    vec3 rvec = texture(noise, texcoord * noiseScale).xyz;
    vec3 tangent = normalize(rvec - normal * dot(rvec, normal));
    vec3 bitangent = cross(normal, tangent);

    return mat3(tangent, bitangent, normal);
}

void main(void){

    vec2 TexCoord = pass_TexCoord;
    vec3 Position = CalcPosition();
    vec3 Normal = normalize(texture(NormalMap, TexCoord).xyz);

    mat3 RotationMatrix = CalcRMatrix(Normal, TexCoord);

    int kernelSize = noiseScale_kernelSize.z;

    float occlusion = 0.0;

    for(int i = 0; i < kernelSize; i++){
        // Get sample position
        vec3 sample = RotationMatrix * kernel[i];
        sample = sample * RADIUS + Position;
        // Project and bias sample position to get its texture coordinates
        vec4 offset = projectionMatrix * vec4(sample, 1.0);
        offset.xy /= offset.w;
        offset.xy = offset.xy * 0.5 + 0.5;
        // Get sample depth
        float sample_depth = texture(DepthMap, offset.xy).r;
        float linearDepth = projAB.y / (sample_depth - projAB.x);
        if(abs(Position.z - linearDepth ) < RADIUS){
            occlusion += (linearDepth <= sample.z) ? 1.0 : 0.0;
        }
    }
    out_AO = 1.0 - (occlusion / kernelSize);
}

我绘制一个全屏四边形并传递“深度”和“法线”纹理。法线在RGBA16F中,其中alpha通道保留给模糊通道中的AO因子。我将深度存储在非线性深度缓冲区(32F)中,并使用以下方法恢复线性深度:


float linearDepth = projAB.y / (depth - projAB.x);

其中projAB.y的计算公式为:

在此处输入图片说明

projAB.x作为:

在此处输入图片说明

这些是从glm :: perspective(gluperspective)矩阵派生的。z_n和z_f是近和远剪辑距离。

如我在顶部发布的链接中所述,该方法在半球中以接近中心的较高分布来创建样本。然后,它使用来自纹理的随机矢量来使半球绕Z方向随机旋转,最后将其沿给定像素处的法线定向。由于结果嘈杂,因此在SSAO通过之后进行模糊通过。

无论如何,我的位置重建似乎没有错,因为我也尝试这样做,但是位置是从纹理传递而不是被重建。

我还尝试过使用Radius,噪波纹理大小和样本数量以及各种纹理格式,但没有运气。由于某些原因,更改半径时不会发生任何变化。

有没有人有什么建议?可能出什么问题了?


我认为模糊需要单独通过。您可以发布没有模糊的着色器的屏幕截图吗?
knight666

模糊过程是单独的,您可以检查预模糊屏幕截图
Grieverheart

Answers:


6

我发现了问题。这是一个非常愚蠢的错误,我不知道您必须指定glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);要获取正确的深度值,因此,我没有对深度值进行采样。现在,我得到了不错的SSAO效果:

在此处输入图片说明


随时将其标记为正确答案,以便人们知道您已经找到了解决方案:P
SomeGuy 2012年

是的,很不幸,我必须等待一天,才能将我的答案标记为正确的:S。
Grieverheart

我的错误,没有检查时间戳。
2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.