GLSL Basics

XXX Moved to the new site.

  1. What is GLSL
    1. A bit of history
    2. What is a Shader
  2. What do you need to use GLSL
    1. Software
    2. Hardware
  3. How to use GLSL
    1. OpenGL and C code
    2. Vertex Processor
    3. Fragment Processor
  4. Examples
    1. Toon shading
      1. Vertex Shader
      2. Fragment shader
    2. Directionnal Light
      1. OpenGL Modifications
      2. Vertex Shader
      3. Fragment Shader
    3. Light Per Pixel
      1. OpenGL Modifications
      2. Vertex Shader
      3. Fragment Shader

What is GLSL

A bit of history

Shaders were born in February with the Nvidia GeForce3 video card. The firsts API that allow you to program with shaders are DirectX8 and OpenGL 1.5.

gf3si8

These two APIs allow you to program shaders. If you want to use the Microsoft DirectX API you will need to write your shaders using HLSL. HLSL stands for High Level Shading Language. Nvidia also developped their own shading language called Cg (C for grapgics). Cg is independant so can be use with any graphics API. In our case we are going to use the OpenGL Shading Language. This shading language is based on the OpenGL graphics language. That means you need to know how to program using OpenGL. [WWW] This Wiki page will help you in this direction.

openglpv2

What is a Shader

Let's have a look at the graphics pipeline. This first picture show you what the Graphics pipeline used to be.

/center/ opengles1xpipelinegm8 /center/

As there were no possibility for coding effects, we had to use Fixed Function to perform each task.

This second picture show you the graphics pipeline since OpenGL 2.0

opengles20pipelinegr4

As you can see the two main parts of the pipeline, colored in orange, have been changed. The transform and lighting step is now fully programable using Vertex shaders. The Texture Environment, Colour Sum and Fog step can be programmed using Fragment shaders.

To give an answer to the title question, a shader is a program that allow you to modify the graphics pipeline at runtime.

What do you need to use GLSL

Software

We are going to code our shaders in C. So you need a C editor. You can se a free software such as DevC++ or COdeBlocks. Nevertheless I am using Visual C++ so all the examples will be given in this format.

Once your C++ editor installed you will need GLSL librairies. The easier way is to install packages. I recommend you Glut and Glew. You can find this packages [WWW] there

Extract the two packages and copy glew32.dll, glut32.dll into C:\WINDOWS\system32

In the include directory (default: C:\Program Files\Microsoft Visual Studio 8\VC\include):

- Create GL directory

- Copy glut and glew headers (glew.h, glut.h, wglew.h) into GL folder (default: C:\Program Files\Microsoft Visual Studio 8\VC\include\GL)

In the lib directory (default: C:\Program Files\Microsoft Visual Studio 8\VC\lib):

- Copy glew32.lib and glew32s.lib into directory

- Copy glut32.lib into directory

Hardware

To run program using shaders you need a GPU that accept shading language. Even if every graphics card since the GeForce3 support shaders, you will need at least a Nvidia Geforce 5200 or ATI 9500 to work properly with OpenGL 2.X Make sure your graphics card drivers are up. OpenGL supports and Shaders Compiler are integrated to the drivers.

How to use GLSL

OpenGL and C code

As I tolld you before, the GLSL requires a valid OpenGL program. We also need to enable the Shading Language. Here is a scheme showing necessary steps to enable Shaders :

activateglslng3

In order to do that, here is a small C program with essentials functions. This code will be the base to every examples I will give later. I won't show you the whole code for every example but only the parts that differs from this original code. Hence I recommend you tu use this code. However feel free to modify it :) Here is the code with comments :

   1 
   2 #include <windows.h>
   3 #include <stdio.h>
   4 #include <string.h>
   5 #include <GL/glew.h>
   6 #include <GL/glut.h>
   7 #include "util.h"
   8 
   9 // Global variables
  10 GLuint program;
  11 GLenum mode = GL_TRIANGLES;
  12 GLfloat angleZ=0;
  13 double camX=0;
  14 
  15 // Init Lights positions
  16 GLfloat pointposition[] = { 4.0f, 1.0f, 2.0f, 1.0f};
  17 
  18 
  19 
  20 void drawObject(){
  21 
  22         
  23         glNormal3f(0,1,0);
  24 
  25         // Draw Teapot
  26         glutSolidTeapot(1.5f);
  27         //glutSolidSphere(1.5f,100,100);
  28 }
  29 void updatefps(){       // This function calculates FPS
  30 
  31         static int fps = 0;     
  32         static float previousTime  = 0.0f;      
  33         static char  strFPS[20]    = {0};
  34         
  35         float currentTime = (GetTickCount() * 0.001f);
  36 
  37     ++fps;      // Increment the FPS counter
  38 
  39         // Display FPS
  40         if( currentTime - previousTime > 1.0f ){
  41                 previousTime = currentTime;
  42                 sprintf(strFPS, "FPS: %d", fps);
  43                 glutSetWindowTitle(strFPS);
  44                 fps = 0;
  45         }
  46 }
  47 void initGlut(int *argc, char **argv)
  48 {
  49         //glut initialisation
  50         glutInit(argc, argv);
  51         glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_MULTISAMPLE);
  52         // create window
  53         glutInitWindowSize(1280, 800);
  54         glutInitWindowPosition(0, 0);
  55         glutCreateWindow("GLSL");
  56         //Init lighting
  57         glEnable(GL_DEPTH_TEST);
  58         glEnable(GL_LIGHTING);
  59         glEnable(GL_LIGHT0);
  60 }
  61 
  62 
  63 void display() {
  64 
  65         float CamPos[3];
  66         CamPos[0]=2;
  67         CamPos[1]=5;
  68         CamPos[2]=2;
  69 
  70         // Create a link to use the CamPos variable in VS and FS
  71         
  72         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  73         glLoadIdentity();
  74 
  75         gluLookAt(CamPos[0],CamPos[1],CamPos[2],0,0,0,0,1,0);
  76         
  77         glRotatef(angleZ,0,1,0);
  78         //glRotatef(20, 0, 0, 1);
  79         //glRotatef(20, 1, 0, 0);
  80         
  81         glLightfv(GL_LIGHT0, GL_POSITION, pointposition);
  82 
  83         drawObject();
  84         
  85         glutSwapBuffers();
  86         updatefps();
  87 
  88 }
  89 void reshape(int w, int h) {
  90 
  91         //Set up an orthographic view of the objects
  92         glViewport(0,0,w,h);
  93         glMatrixMode(GL_PROJECTION);
  94         glLoadIdentity();
  95         gluPerspective(70, 16.0/10.0, 0.001, 1000);
  96         glMatrixMode(GL_MODELVIEW);
  97 }
  98 void idle() // Render as fast as possible
  99 {
 100         glutPostRedisplay();
 101 }
 102 
 103 void events1(unsigned char key, int x, int y)
 104 {
 105         switch(key) {
 106                 case GLUT_KEY_RIGHT : 
 107                                 angleZ++;
 108                                 break;
 109                 case GLUT_KEY_LEFT : 
 110                                 angleZ--; 
 111                                 break;
 112                 /*
 113                 case GLUT_KEY_UP :
 114                                 camX++;
 115                                 break;
 116                 case GLUT_KEY_DOWN :
 117                                 camX--;
 118                                 break;
 119                 */
 120                 case GLUT_KEY_UP:
 121                         pointposition[0] += 0.2;
 122                         break;          
 123                 case GLUT_KEY_DOWN:
 124                         pointposition[1] -= 0.2;
 125                         break;
 126         }
 127 }
 128 void events2(unsigned char key, int x, int y)
 129 {
 130         printf("key: %d\n", key);
 131 }
 132 
 133 void initGLSL(){
 134 
 135         const char *verstr;
 136         const char *verglsl;
 137         GLuint vs, fs;
 138         GLuint compileResults[3];
 139         char infoLog[500];
 140 
 141         // Enable Shading Language
 142         verstr  = (const char *)glGetString(GL_VERSION);
 143         verglsl = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
 144         printf("%s\n", verstr);
 145         printf("%s\n", verglsl);
 146 
 147         vs = loadShader("vertex.txt", GL_VERTEX_SHADER);
 148         fs = loadShader("fragment.txt", GL_FRAGMENT_SHADER);
 149 
 150 
 151         // Compile Vertex Shader
 152         glCompileShader(vs);
 153         glGetShaderiv(vs, GL_COMPILE_STATUS, compileResults);
 154         if((*compileResults) == GL_TRUE){
 155                 printf("VertexShader...OK!\n");
 156         }else{
 157                 glGetShaderInfoLog(vs, 200, NULL, infoLog);
 158                 printf("%s", infoLog);
 159         }
 160 
 161         // Compile Fragment Shader
 162         glCompileShader(fs);
 163         glGetShaderiv(fs, GL_COMPILE_STATUS, compileResults);
 164         if((*compileResults) == GL_TRUE){
 165                 printf("FragmentShader...OK!\n");
 166         }else{
 167                 glGetShaderInfoLog(fs, 200, NULL, infoLog);
 168                 printf("%s", infoLog);
 169         }
 170 
 171         // Attach,Link and Use Shaders
 172         program = glCreateProgram();
 173         glAttachShader(program, vs);
 174         glAttachShader(program, fs);
 175         glLinkProgram(program);
 176         glUseProgram(program);
 177 
 178         glGetProgramiv(program, GL_LINK_STATUS, compileResults);
 179         if((*compileResults) == GL_TRUE){
 180                 printf("Linking successful");
 181                 
 182         }
 183 }
 184 
 185 
 186 
 187 int main(int argc, char **argv){
 188 
 189         // variables
 190         GLenum err;
 191 
 192         // Initialize Glut
 193         initGlut(&argc, argv);
 194         
 195         // Check Glew
 196         err = glewInit();
 197         printf("%s\n", glewGetString(GLEW_VERSION));
 198 
 199         //Initialize GLSL
 200         initGLSL();
 201         
 202         // Display
 203         glutDisplayFunc(display);
 204         glutReshapeFunc(reshape);
 205         glutIdleFunc(idle);
 206         
 207         //events
 208         glutSpecialFunc(events1);
 209         glutKeyboardFunc(events2);
 210 
 211         //Set Background Color
 212         glClearColor(1.0, 1.0, 1.0, 1.0);
 213         //glCullFace(GL_FRONT_AND_BACK);
 214         //glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
 215         glutMainLoop();
 216         glDeleteProgram(program);
 217 
 218 }
 219 
 220 

As you can see, the function LoadShader is not declared in this code. Here is the util.c code for that :

   1 
   2 #include <GL/glew.h>
   3 #include <stdio.h>
   4 #include "util.h"
   5 #include <stdlib.h>
   6 
   7 /*
   8  Create shader instance and read source form file system
   9  */
  10 
  11 
  12 GLuint loadShader(const char * srcPath, GLenum shaderType){
  13         GLuint shader = glCreateShader(shaderType);
  14         FILE * fp = fopen(srcPath, "r");
  15         char * src = read(fp);
  16         fclose(fp);
  17         glShaderSource(shader, 1, &src, NULL);
  18         free(src);
  19         return shader;
  20 }
  21 
  22 char * read(FILE * fp){
  23         char * text;
  24         long chars;
  25 
  26         fseek(fp, 0L, SEEK_END);     /* Position to end of file */
  27         chars = ftell(fp);
  28         rewind(fp);
  29         text = (char*)calloc(chars, sizeof(char));      
  30         fread(text, sizeof(char), chars, fp);
  31         printf("%s\n", text);
  32         return text;
  33 }
  34 

And here is the util.h header :

   1 
   2 #include <stdio.h>
   3 #include <GL/glew.h>
   4 
   5 extern
   6 GLuint loadShader(const char * srcPath, GLenum shaderType);
   7 
   8 extern
   9 char * read(FILE * fp);
  10 

Create an empty project and add 2 new C Source Files, main.c and util.c. Then copy/paste the corresponding code above. Do the same for the util Header file. Now, create 2 new text files in your program directory and name them vertex.txt and fragment.txt . These files will contain the vertex and fragment programs. For the moment just write an empty void main function in each program :

   1 void main()
   2 {
   3 }

You can add these 2 text files to make them easier to read and to modify. Your workspaceshould looks like that now

workspacecx3

To run properly, this Application need Additionnal dependencies. Add glut32.lib glew32.lib opengl32.lib to the corresponding line in the Property Pages. Right click on your pogram name->Properties->Configuration Properties->Linker->Input and copy paste the line above in bolt characters.

Compile and run the program, you should see a beautiful teapot enlighten by a spot light. The arrows keys allow you to rotate the teapot and translate the light position. However I encourage you to choose your owne keys and transformations.

teapotwithoutshadershn4

For the moment nothing different, that's only basics OpenGL. But you probably noticed the ms-dos window in the background. This window dipslays the vertex and fragment code and inform you if it compiles well or not. A line is missing in this case, "linking succesfull". Nothing's wrong as our shaders are empty.

msdoswindowrb2

Remember! : Your openGl code is compiled by your C editor. But Shaders are compiled bye the compiler included in your graphics driver. This last one automaticaly compiles as you run your OpenGL program, so non need to recompile if you only change shaders code.

Let's program Shaders now !

Vertex Processor

This paragraph introduce the vertex processor. It is probably a bit abstract so don't worry if you don't understand everything. The examples in the last chapter will refer to this paragraph and things will be clearer then.

Here is the definition given in the referenced Orange Book, OpenGL Shading Language by Randi J.Rost :

"The vertex processor executes a vertex shader and replaces the following fixed functionnality OpenGL per-vertex operations.A vertex shader has no knowledge of the primitive type for the vertex it is working on. The vertex processor is a programmable unit that operates on incoming values and their associated data. The vertex processor is intended to perform traditionnal graphics operations such as the following :

i. Vertex transformation i. Normal transformation and normalization i. Texture coordinate generation i. Texture coordinate transformation i. Lighting i. Color material application

dscf9885ie0

Here are the rules, given in the Orange Book (OpenGL Shading Language by Randi J.Rost, simply indispensable) respected in the vertex processor. Have a look at these and don't hesitate to come back to this paragraph when you'll be programming:

* The modelview matrix is not applied to vertex coordinates. * The projection matrix is not applied to vertex coordinates. * The texture matrices is notapplied to texture coordiantes. * Normals are not transformed to eye coordinates. * Normals are not rescaled or normalized. * Normalization of GL_AUTO_NORMAL evaluated normals is not performed. * Texture coordinates are not generated automatically. * Per-vertex lighting is not performed. * Color computations are not performed. * Color index lighting is not performed. * Point size distance attenuation is not performed. * All of the preceding applies when setting the current raster position.

The following fixed functionality operations are applied to vertex values that are the result of executing the vertex shader:

* Color clamping or masking * Perspective division on clip coordinates * Viewport mapping * Depth range * Clipping, including user clipping * Front face determination * Flat-shading * Color, texture coordinate, fog, point size and user-defined varying clipping * Final color processing

Keep in mind that the vertex processor is comes before the fragment processor in the GLSL machine. A look at the two pictures will confirm you that. So think about that while programming shaders. This may help you in many cases.

Now let's have a look at the Fragment Processor.

Fragment Processor

Here is the definition of the Fragment Processor given by the Orange Book :

The Fragment Processor is a programmable unit that operates on fragment values and their associated data. The fragment processor is intended to perform traditional graphics operations such as the following :

i. Operations on interpolated values i. Texture access i. Texture application i. Fog i. Color sum

dscf9886wa1

The fragment shader is working at the pixel scale. The main job of the pixel shader is to apply a color to every pixel through the gl_FragColor function. The pixel shader also work on the pixel depth trough "gl_FragDepth".

Examples

Toon shading

The first question you have to ask yourself is "What efect to you want to make ?". I recommend you to draw or to find something on internet to kown exactly what effect you want.

For this first example, here is a good picture presenting exactly what I want to do.

sharktsyx8

This is not especially good looking but keep in mind this is our very first shader. As you can see, the shader as to the 3D object

Now let's go to the second main question, "What part of code belongs to the vertex shader, and what part belongs to the fragment shader ?"

The Toon shader can be split in two. In one hand we want to color in black the contour. In the other hand, we want to replace the continous color management by a step function.

Vertex Shader

In the vertex shader you can and you have to do all operations relatives to vertex. So even if you want to apply color to a vertex, which is relative to the fragment shader, you have to use the varying parameter. This is the case for the border of the object. We need to detect the boarder but we also want to color them in black.

You should agree if I say a vertex belongs to the boarder if the normal of this vertex is perpendicular to the vector going from eye coordinates to this vertex. In mathematics terms, edge = max(dot(cameraVector,n),0); Yes I also found maths langages clearer sometimes ...

So the camera vector is: vec3 cameraVector = normalize (CAMERA_POSITION - M);

Where M is the coordinates of the vertex : vec3 M = gl_Position.xyz;

CAMERA_POSITION is a uniform variable. Which means you have to define the camera position as a uniforma variable in the OpenGL source program :

   1 GLint uni;
   2 
   3 uni = glGetUniformLocation(program, "CAMERA_POSITION");
   4 glUniform3fv(uni,3, CamPos);

Will add these lines of code in the display function.

In the vertex program, just add : uniform vec3 CAMERA_POSITION; will allow you to use this variable.

I would like to remind you the edge calculation mehod : edge = max(dot(cameraVector,n),0); For now we explained cameraVector, what about n ? n is usually used for the vertex normal, once normalized :vec3 n = normalize(normal); The use of normalized vector is highly recommended in most cases to avoid sign and length troubles.

Last things to include to the vertex shader. We know we want to use edge,and normal variables in the shader program. In this purpose we need to declare them as varying variables.

   1 varying vec3 normal;
   2 varying float edge;

Now we can use them in the Pixel shader program.

Here is, to resume, the complete Vertex program.

   1 // Vertex Shader code
   2 
   3 
   4         varying vec3 normal;
   5         varying float edge;
   6         uniform vec3 CAMERA_POSITION;
   7         
   8         void main()
   9         {
  10                                 
  11                 normal = gl_NormalMatrix * gl_Normal;
  12                 
  13                 gl_Position = gl_ModelViewMatrix * gl_Vertex;
  14                 
  15                 vec3 M = gl_Position.xyz;
  16                 vec3 n = normalize(normal);
  17                 vec3 cameraVector = normalize (CAMERA_POSITION - M);
  18                 
  19                 edge = max(dot(cameraVector,n),0);
  20                 
  21                 gl_Position=ftransform();
  22 
  23 
  24         } 

gl_Position=ftransform(); is a fundamental function. It applicates the transfomration between the 3D and your screen. I can be replaced by gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;. But this second can create some artifacts depending on the way OpenGL implemented. Anyway, use the first one !

Let's move to the fragement program !

Fragment shader

The toon effect we want to realize can be seen as infinite ways. To make that easy and to have an effect close to the one on the picture example we will define a new variable, intensity defined as : intensity = dot(vec3(gl_LightSource[0].position),n);

gl_LightSource[i] is a built-in varialbe for the ith light source. Through this variable we have directly access to every Light[i] parameter declared in the OpenGL program : position,diffuse,specular...

In our case we would like to use the Light[0] parameter, so we'll use the gl_LightSource[0].position command.

n is the normalized normal to each vertex. It has been declared as a varying parameter, so we need to add these lines :

   1 varying vec3 normal;
   2 vec3 n = normalize(normal);

To create the Toon effect, we wanted to replace the continous light by a discret one. Let's take 4 values and for this ones replace the light by a color. So let's say that :

   1                if (edge < 0.3)
   2                         color = vec4(0.0,0.0,0.0,1.0);
   3                 else if (intensity > 0.95)
   4                         color = vec4(0.5,0.5,1.0,1.0);
   5                 else if (intensity > 0.6)
   6                         color = vec4(0.3,0.3,0.6,1.0);
   7                 else if (intensity > 0.25)
   8                         color = vec4(0.2,0.2,0.4,1.0);
   9                 else
  10                         color = vec4(0.1,0.1,0.2,1.0);

Everything we want has been done, we just need to applicate the color to pixels through the gl_FragColor function.

Here is the complete Fragment Shader code :

   1 // Fragment Shader code
   2 
   3         varying vec3 normal;
   4         varying float edge;
   5         
   6         
   7         void main()
   8         {
   9                 
  10                 float intensity;
  11                 vec4 color;
  12                 vec3 n = normalize(normal);
  13 
  14                 intensity = dot(vec3(gl_LightSource[0].position),n);
  15                 
  16                 if (edge < 0.3)
  17                         color = vec4(0.0,0.0,0.0,1.0);
  18                 else if (intensity > 0.95)
  19                         color = vec4(0.5,0.5,1.0,1.0);
  20                 else if (intensity > 0.6)
  21                         color = vec4(0.3,0.3,0.6,1.0);
  22                 else if (intensity > 0.25)
  23                         color = vec4(0.2,0.2,0.4,1.0);
  24                 else
  25                         color = vec4(0.1,0.1,0.2,1.0);
  26                         
  27                 gl_FragColor = color;
  28                 
  29         } 

On your screen, this should looks like that :

yeeeesssssssssssgj5

ok, now you are a bit familiar with shaders. What about playing a bit with lighting ?

Directionnal Light

OpenGL Modifications

   1 // Init Lights specifications
   2 GLfloat pointposition[] = { 4.0f, 1.0f, 2.0f, 1.0f};
   3 GLfloat light_ambient[] = { 1.0, 0.0, 0.0, 1.0 }; 
   4 GLfloat light_diffuse[] = { 0.0, 0.1, 0.2, 1.0 };
   5 
   6 // Init Material specifications
   7 GLfloat mat_ambient[]={0.25, 0,25, 0,25};
   8 GLfloat mat_diffuse[]={0.2, 0.8, 0.1};
   1 void drawObject(){
   2         
   3         // Assign Specifications to material
   4         glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
   5         glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
   6 
   7         glNormal3f(0,1,0);
   8         glutSolidTeapot(1.5f);
   9         //glutSolidSphere(1.5f,100,100);
  10 }
   1         glLightfv(GL_LIGHT0, GL_POSITION, pointposition);
   2         glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
   3         glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); 

Vertex Shader

   1 // Vertex Shader Code //
   2 
   3 void main()
   4         {       
   5                 
   6                 vec3 normal, lightDir;
   7                 vec4 diffuse, ambient, globalAmbient;
   8                 float NdotL;
   9                 
  10                 normal = normalize(gl_NormalMatrix * gl_Normal);
  11                 lightDir = normalize(vec3(gl_LightSource[0].position));
  12                 NdotL = max(dot(normal, lightDir), 0.0);
  13                 diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
  14                 
  15                 /* Compute the ambient and globalAmbient terms */
  16                 
  17                 ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
  18                 globalAmbient = gl_LightModel.ambient * gl_FrontMaterial.ambient;
  19                 
  20                 gl_FrontColor =  NdotL * diffuse + globalAmbient + ambient;
  21                 
  22                 gl_Position = ftransform();
  23                 
  24         }

Fragment Shader

   1 // Fragment Shader code
   2 
   3         void main()
   4         {
   5                 gl_FragColor = gl_Color;
   6         }

Light Per Pixel

OpenGL Modifications

   1 // Init Lights positions and specs
   2 
   3 GLfloat pointposition[] = { 6.0f, 5.0f, 6.0f, 1.0f };
   4 GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 }; 
   5 GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; 
   6 GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 }; 
   7 
   8 
   9 // Init Material spec
  10 
  11 GLfloat mat_ambient[]={0.25, 0,25, 0,25};
  12 GLfloat mat_diffuse[]={0.4, 0.4, 0.4};
  13 GLfloat mat_specular[]={ 0.774597, 0.774597, 0.774597};
  14 GLfloat mat_shininess[]={50};
   1 void drawObject(){
   2         
   3         glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
   4         glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
   5         glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
   6         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
   7 
   8         glNormal3f(0,1,0);
   9 
  10         glutSolidTeapot(1.5f);
  11         //glutSolidSphere(1.5f,100,100);
  12         //glutSolidCube(1.5f);
  13 }
   1         glLightfv(GL_LIGHT0, GL_POSITION, pointposition);
   2         glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
   3         glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); 
   4         glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); 

Vertex Shader

// Vertex Shader code

   1         varying vec4 diffuse,ambient;
   2         varying vec3 normal,lightDir,halfVector;
   3         
   4         void main()
   5         {       
   6                 /* first transform the normal into eye space and 
   7                 normalize the result */
   8                 normal = normalize(gl_NormalMatrix * gl_Normal);
   9                 
  10                 /* now normalize the light's direction. Note that 
  11                 according to the OpenGL specification, the light 
  12                 is stored in eye space. Also since we're talking about 
  13                 a directional light, the position field is actually direction */
  14                 lightDir = normalize(vec3(gl_LightSource[0].position));
  15         
  16                 /* Normalize the halfVector to pass it to the fragment shader */
  17                 halfVector = normalize(gl_LightSource[0].halfVector.xyz);
  18                                         
  19                 /* Compute the diffuse, ambient and globalAmbient terms */
  20                 diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
  21                 ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
  22                 ambient += gl_LightModel.ambient * gl_FrontMaterial.ambient;
  23         
  24                 gl_Position = ftransform();
  25         } 

Fragment Shader

   1 // Fragment Shader code
   2 
   3         varying vec4 diffuse,ambient;
   4         varying vec3 normal,lightDir,halfVector;
   5         
   6         
   7         void main()
   8         {
   9                 vec3 n,halfV;
  10                 float<