Shaders, Part 2 – Lighting

Unnamed QQ Screenshot2-1I said last week we’ll be seeing this game very soon, but I didn’t think we’ll be using this game as an good example so fast.

This week, we get into lighting.

In a physic perceptive, a ray of light is generated by a light source and projected to a surface. However, in rendering, a ray of light is just some pixels that’s colored differently from a certain source. This is where shaders came in. As we can see in the above image, the room itself is dark, but thanks to the TV, the areas around the TV has become a different color and stands out in the dark room.

We can already do the lighting in vanilla OpenGL without using any sort of shaders since OpenGL comes with a set of methods to manipulate lighting. However, it can only do a single light at a time and if you want to use a effect that’s similar to what’s in that screenshot, it will not only take a large chunk of code, but also a very large amount of time in order for OpenGL to rendering all the light sources.

In most of the cases, lighting is done by combining 3 different sets of lights/reflections:

  • Ambient
  • Diffuse
  • Specular

This is a technique known as Phong Shading and is one of the common ways to calculate lighting without large chunk of code and endless running times. It’s also more close to the real life lighting of objects.

While I’m doing my assignment for this week, I used Phong Shading by first creating 4 lights around one object in different locations outside the viewport then executes the shading process on the item itself. This generates an effect where the object in question is initially of the color of the ambient light but when spinning and rotating around, the different parts of the object changes color as different parts reflect off a different light source. Normally in OpenGL, this would be a huge hassle but with GLSL, it becomes something very easy:

Vertex Shader:

varying vec3 N; 
varying vec3 v; 
void main(void) { 
v = vec3(gl_ModelViewMatrix * gl_Vertex); 
N = normalize(gl_NormalMatrix * gl_Normal); 
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
}

Fragment Shader:

varying vec3 N;
varying vec3 v;

void main (void)
{
vec3 L = normalize(gl_LightSource[0].position.xyz - v);
vec3 E = normalize(-v); // we are in Eye Coordinates, so EyePos is (0,0,0)
vec3 R = normalize(-reflect(L,N));
//calculate Ambient Term:
vec4 Iamb = gl_FrontLightProduct[0].ambient;
//calculate Diffuse Term:
vec4 Idiff = gl_FrontLightProduct[0].diffuse * max(dot(N,L), 0.0);
// calculate Specular Term:
vec4 Ispec = gl_FrontLightProduct[0].specular
* pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess);
// write Total Color:
gl_FragColor = gl_FrontLightModelProduct.sceneColor + Iamb + Idiff + Ispec;
}

The result, if I could comment on it, is even better than I expected.

So, until next week.

 

Post a Comment