# 5. GLSL Per Pixel Lighting

This tutorial is going to be quite simple. To achieve the effect of per pixel lighting, we simply need to move one calculation from our vertex shader to our fragment shader.

So lets go to it!

Main.CPP File:

Just for the sake of it, I have switched to a glutSolidTeapot for this tutorial. It will come on handy when testing different effects.

 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. #if ( (defined(__MACH__)) && (defined(__APPLE__)) )    #include #include #include #include #else #include #include #include #include #include #endif #include “shader.h” Shader shader; GLfloat angle = 0.0; //set the angle of rotation //diffuse light color variables GLfloat dlr = 1.0; GLfloat dlg = 1.0; GLfloat dlb = 1.0; //ambient light color variables GLfloat alr = 0.0; GLfloat alg = 0.0; GLfloat alb = 0.0; //light position variables GLfloat lx = 0.0; GLfloat ly = 1.0; GLfloat lz = 1.0; GLfloat lw = 0.0; void init(void) {     glEnable(GL_DEPTH_TEST);     glDepthFunc(GL_LESS);          shader.init(“shader.vert”, “shader.frag”); } void cube (void) {     glRotatef(angle, 1.0, 0.0, 0.0); //rotate on the x axis     glRotatef(angle, 0.0, 1.0, 0.0); //rotate on the y axis     glRotatef(angle, 0.0, 0.0, 1.0); //rotate on the z axis     glColor4f(1.0, 0.0, 0.0, 1.0);     glutSolidTeapot(2); } void setLighting(void) {     GLfloat DiffuseLight[] = {dlr, dlg, dlb}; //set DiffuseLight[] to the specified values     GLfloat AmbientLight[] = {alr, alg, alb}; //set AmbientLight[] to the specified values          glLightfv (GL_LIGHT0, GL_DIFFUSE, DiffuseLight); //change the light accordingly     glLightfv (GL_LIGHT0, GL_AMBIENT, AmbientLight); //change the light  accordingly          GLfloat LightPosition[] = {lx, ly, lz, lw}; //set the LightPosition to the specified values          glLightfv (GL_LIGHT0, GL_POSITION, LightPosition); //change the light accordingly } void display (void) {     glClearColor (0.0,0.0,0.0,1.0);     glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);     glLoadIdentity();       gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);          setLighting();          shader.bind();     cube();     shader.unbind();          glutSwapBuffers();     angle += 0.01f; } void reshape (int w, int h) {     glViewport (0, 0, (GLsizei)w, (GLsizei)h);     glMatrixMode (GL_PROJECTION);     glLoadIdentity ();     gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);     glMatrixMode (GL_MODELVIEW); } int main (int argc, char **argv) {     glutInit(&argc, argv);     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); //set up the double buffering     glutInitWindowSize(500, 500);     glutInitWindowPosition(100, 100);     glutCreateWindow(“A basic OpenGL Window“);          glewInit();     glutDisplayFunc(display);     glutIdleFunc(display);          glutReshapeFunc(reshape);          init();          glutMainLoop();          return 0; }

In the last tutorial, to achieve lighting, we had one varying variable called diffuse_value. In this tutorial, we are going to remove this varying, and create two others. One of them is going to contain the vertex_light_position, and the other is going to contain the vertex_normal:

varying vec3 vertex_light_position;
varying vec3 vertex_normal;

Now we need to store some values in here. This is collected the exact same way as last time:

vertex_normal = normalize(gl_NormalMatrix * gl_Normal);

vertex_light_position = normalize(gl_LightSource.position.xyz);

And that’s all their is in the vertex shader. Note that I have removed the diffuse_value variable.

 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. varying vec3 vertex_light_position; varying vec3 vertex_normal; void main() {                 // Calculate the normal value for this vertex, in world coordinates (multiply by gl_NormalMatrix)     vertex_normal = normalize(gl_NormalMatrix * gl_Normal);     // Calculate the light position for this vertex     vertex_light_position = normalize(gl_LightSource.position.xyz);     // Set the front color to the color passed through with glColor*f     gl_FrontColor = gl_Color;     // Set the position of the current vertex      gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; }

Since I changed the varying variables in the Vertex Shader, I also need to update them in the fragment shader:

varying vec3 vertex_light_position;
varying vec3 vertex_normal;

Now, if you remember the diffuse_value calculation from the previous tutorial, it has been pretty much copied and pasted into this tutorial, only now it resides inside the fragment shader:

float diffuse_value = max(dot(vertex_normal, vertex_light_position), 0.0);

And that is all their is to it. We now have per pixel lighting. That wasn’t too hard 🙂

If you have any questions, please email me at swiftless@gmail.com

 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. varying vec3 vertex_light_position; varying vec3 vertex_normal; void main() {     // Set the diffuse value (darkness). This is done with a dot product between the normal and the light     // and the maths behind it is explained in the maths section of the site.     float diffuse_value = max(dot(vertex_normal, vertex_light_position), 0.0);     // Set the output color of our current pixel     gl_FragColor = gl_Color * diffuse_value; }