Getting ready

First, let's build our random kernel. We need a set of points in the positive-z hemisphere centered at the origin. We'll use a hemisphere with a radius of 1.0 so that we can scale it to any size as needed:  

int kernSize = 64;
std::vector<float> kern(3 * kernSize);
for (int i = 0; i < kernSize; i++) {
glm::vec3 randDir = rand.uniformHemisphere();
float scale = ((float)(i * i)) / (kernSize * kernSize);
randDir *= glm::mix(0.1f, 1.0f, scale);

kern[i * 3 + 0] = randDir.x;
kern[i * 3 + 1] = randDir.y;
kern[i * 3 + 2] = randDir.z;
}

The uniformHemisphere function chooses a random point on the surface of the hemisphere in a uniform fashion. The details of how to do this were covered in an earlier recipe (see Diffuse image based lighting). To get a point within the hemisphere, we scale the point by the variable scale. This value will vary from 0 to 1 and is non-linear. It will produce more points close to the origin and fewer as we move away from the origin. We do this because we want to give slightly more weight to things that are close to the surface point.

We assign the values of the kernel points to a uniform variable (array) in our shader named SampleKernel.

As mentioned earlier, we want to re-use this kernel for each surface point, but with a random rotation. To do so, we'll build a small texture containing random rotation vectors. Each vector will be a unit vector in the x-y plane:

int size = 4;
std::vector<GLfloat> randDirections(3 * size * size);
for (int i = 0; i < size * size; i++) {
glm::vec3 v = rand.uniformCircle();
randDirections[i * 3 + 0] = v.x;
randDirections[i * 3 + 1] = v.y;
randDirections[i * 3 + 2] = v.z;
}
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB16F, size, size);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, GL_RGB, GL_FLOAT, randDirections.data());
// ...

The uniformCircle function gives a random point on the unit circle in the x-y plane. We're using a 4 x 4 texture here, but you could use a larger size. We'll tile this texture across the screen, and we'll make it available to the shader (uniform variable RandTex).

You might be thinking that a 4 x 4 texture is too small to give us enough randomness. Yes, it will produce high-frequency patterns, but the blur pass will help to smooth that noise out.

In this example, we'll use a single shader and a single framebuffer. You could, of course, use several if desired. We'll need framebuffer textures for the camera space position, camera space normal, base color, and ambient occlusion. The AO buffer can be a single channel texture (for example, format R_16F). We'll also need one additional AO texture for the blur pass. We will swap each one into the framebuffer as necessary.

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

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