Friday, February 15, 2013

Shadows in OpenGL. GLSL implementation

Computer graphics has several techniques for creating shadows:
1) Shadow Mapping
2) Shadow Volumes

I'd like to talk about Shadow Mapping, because it's relatively easy to implement, and I have already made class for rendering scene or some part of the scene to the texture using FBO. Thats why Shadow Mapping algorithm will be based on FBO.

Shadow Mapping Algorithm (2pass algorithm, 1st pass - generating shadow map, 2nd pass - drawing the shadow):

1 st pass:
a) we assume the light source has a “view frustum” just like a camera
b) render scene from light source’s position
c) save depth values only
d) we end up with a shadow (depth-) map

2ndpass
a) render scene as usual, but transform vertices to light space, too
b) for each fragment, compare rasterized fragment depth to previously stored depth (read it from shadow map)
b1) zfragment > zfrom_shadow_map => fragment lies in shadow
c) both fragments must be in light space

It's an example of how you can do this. Implementation of shadow mapping I'm going to cover later with detailed review

First of all CREATE AN FBO! For this you should use Fixed Function Pipeline of OpenGL

Vertex Shader:


#version 140

uniform mat4 M;               // model matrix
uniform mat4 V_cam;       // view matrix for the camera
uniform mat4 P_cam;       // projection matrix for the camera
uniform mat4 texture_matrix;
in vec4 vertex;                 // from the application
out vec4 SM_tex_coord; // pass on to the FS

void main(void) {
      // standard transformation
      gl_Position = P_cam * V_cam * M * vertex;
      // shadow texture coords in projected light space
      SM_tex_coord = texture_matrix * V_cam * M * vertex;
}



Fragment Shader:


#version 140

uniform sampler2D shadow_map;
in vec4 SM_tex_coord;       // passed on from VS
out vec4 fragment_color;    // final fragment color destination

void main(void) {
      // note the perspective division!
      vec3 tex_coords = SM_tex_coord.xyz/SM_tex_coord.w;
     // read depth value from shadow map
     float depth = texture(shadow_map, tex_coords.xy).r;
     float inShadow = (depth < tex_coords.z) ? 1.0 : 0.0;
     // do something with that value ...
}