| |
 |
5. Basic Per Pixel Lighting in GLSL
|
|
If you would like to see this site updated, please help out and
|
Jump To:
main.cpp Source
shader.vert Source
shader.frag Source
Download
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 <stdlib.h>
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#include <OpenGL/glext.h>
#else
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glut.h>
#include <GL/glext.h>
#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");
glutDisplayFunc(display);
glutIdleFunc(display);
glutReshapeFunc(reshape);
init();
glutMainLoop();
return 0;
}
|
|
Vertex Shader Source:
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[0].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[0].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;
}
|
|
Fragment Shader Source:
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;
}
|
|
|
Download:
Download shader.h Source Code for this Tutorial
Download shader.cpp Source Code for this Tutorial
Download main.cpp Source Code for this Tutorial
Download shader.vert Source Code for this Tutorial
Download shader.frag Source Code for this Tutorial
|
Comments:
|
 |