#version 330 core
out float FragColor;
in vec2 TexCoords;
uniform sampler2D gPositionDepth;
uniform sampler2D gNormal;
uniform sampler2D texNoise;
uniform vec3 samples[];
int kernelSize = ;
float radius = 1.0;
const vec2 noiseScale = vec2(800.0f/4.0f, 600.0f/4.0f);
uniform mat4 projection;
void main()
{
vec3 fragPos = texture(gPositionDepth, TexCoords).xyz;
vec3 normal = texture(gNormal, TexCoords).rgb;
vec3 randomVec = texture(texNoise, TexCoords * noiseScale).xyz;
vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
vec3 bitangent = cross(normal, tangent);
mat3 TBN = mat3(tangent, bitangent, normal);
float occlusion = 0.0;
for(int i = 0; i < kernelSize; ++i)
{
vec3 sample = TBN * samples[i];
sample = fragPos + sample * radius;
vec4 offset = vec4(sample, 1.0);
offset = projection * offset;
offset.xyz /= offset.w;
offset.xyz = offset.xyz * 0.5 + 0.5;
float sampleDepth = -texture(gPositionDepth, offset.xy).w;
float rangeCheck = smoothstep(0.0, 1.0, radius / abs(fragPos.z - sampleDepth ));
occlusion += (sampleDepth >= sample.z ? 1.0 : 0.0) * rangeCheck;
}
occlusion = 1.0 - (occlusion / kernelSize);
FragColor = occlusion;
}
在 SSAO 算法中,我们生成了若干个随机采样点,比如上面的个samples,虽然这些samples是随机的,但是却每个像素都相同,这样效果并不好,因此可以通过引入随机旋转向量,使每个像素在计算时,把采样点们绕着法线旋转随机角度来引入一些随机性。这里的随机旋转向量是用4x4的纹理来存放的(texNoise,4x4的纹理 16个随机旋转向量基本够用,弄个800x600的全部都是随机的旋转向量没必要,代价太大,效果提升很小。 ),并传入ssao过程的shader中。这些随机旋转向量通常是在切线空间中定义的,每个像素在计算时都从noise纹理中采样一个随机旋转向量randomVec并且用它跟视图空间中的normal来构造一个切线空间,计算获得TBN矩阵,然后每个像素采样得到的旋转向量是不同的 因此TBN是不太一样的。这样,在把samples 转换到 视图空间的时候,分布就会不太一样。