How to do it...

  1. In the first pass, render the scene to the geometry buffers (see Using deferred shading for details).
  2. In the second pass, we'll use this fragment shader code to compute the AO factor. To do so, we first compute a matrix for converting the kernel points into camera space. When doing so, we use a vector from RandTex to rotate the kernel. This process is similar to computing the tangent space matrix in normal mapping. For more on this, see Using normal maps:
// Create the random tangent space matrix
vec3 randDir = normalize( texture(RandTex, TexCoord.xy * randScale).xyz );
vec3 n = normalize( texture(NormalTex, TexCoord).xyz );
vec3 biTang = cross( n, randDir );
// If n and randDir are parallel, n is in x-y plane
if( length(biTang) < 0.0001 )
biTang = cross( n, vec3(0,0,1));
biTang = normalize(biTang);
vec3 tang = cross(biTang, n);
mat3 toCamSpace = mat3(tang, biTang, n);
  1. Then, we compute the ambient occlusion factor by looping over all of the kernel points, transforming them into camera coordinates, and then finding the surface point at the same (x,y) position and comparing the z values. We write the result to the AO buffer:
float occlusionSum = 0.0;
vec3 camPos = texture(PositionTex, TexCoord).xyz;
for( int i = 0; i < kernelSize; i++ ) {
vec3 samplePos = camPos + Radius * (toCamSpace * SampleKernel[i]);

// Project point to texture space
vec4 p = ProjectionMatrix * vec4(samplePos,1);
p *= 1.0 / p.w;
p.xyz = p.xyz * 0.5 + 0.5;

// Camera space z-coordinate of surface at the x,y position
float surfaceZ = texture(PositionTex, p.xy).z;
float dz = surfaceZ - camPos.z;

// Count points that ARE occluded within the hemisphere
if( dz >= 0.0 && dz <= Radius && surfaceZ > samplePos.z )
occlusionSum += 1.0;
}

AoData = 1.0 - occlusionSum / kernelSize;
  1. In the third pass, we do a simple blur, using a unweighted average of the nine nearest pixels. We read from the texture that was written in the previous pass, and write the results to our second AO buffer texture:
ivec2 pix = ivec2( gl_FragCoord.xy );
float sum = 0.0;
for( int x = -1; x <= 1; ++x ) {
for( int y = -1; y <= 1; y++ ) {
sum += texelFetchOffset( AoTex, pix, 0, ivec2(x,y) ).r;
}
}
AoData = sum / 9.0;
  1. The fourth pass applies the reflection model using the ambient occlusion value from the previous pass. We scale the ambient portion by the value in the AO buffer raised to the fourth power (to slightly exaggerate the effect):
vec3 pos = texture( PositionTex, TexCoord ).xyz;
vec3 norm = texture( NormalTex, TexCoord ).xyz;
vec3 diffColor = texture(ColorTex, TexCoord).rgb;
float aoVal = texture( AoTex, TexCoord).r;

aoVal = pow(aoVal, 4);
vec3 ambient = Light.La * diff * aoVal;
vec3 s = normalize( vec3(Light.Position) - pos);
float sDotN = max( dot(s,norm), 0.0 );
vec3 col = ambient + Light.L * diff * sDotN;

col = pow(col, vec3(1.0/2.2)); // Gamma

FragColor = vec4(col, 1.0);

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.21.93.44