OpenGL Shader Language (GLSL)

CS 493 Lecture, Dr. Lawlor

GLSL is the standard language today for describing the code used to drawing pixel to the screen on modern graphics cards.

Non-Programmable Shaders Stink

Back in the day (2000 AD), graphics cards had finally managed to compute all of OpenGL in hardware.  They had hardware projection matrices, hardware clipping, hardware transform-and-lighting, hardware texturing, and so on.  Folks were thrilled, because glQuake looked amazing and ran great.

There's a problem with hardware, though.  It's hard to change.

And no two programmers ever want to do, say, bump mapping exactly the same way.  Some want shadows.  Some want bump-and-reflect.  Some want bump-and-light.  Some want light-and-bump.  nVidia and ATI were going crazy trying to support every developer's crazy desires in hardware.  For example, my ATI card still supports these OpenGL extensions, just for variations on bump/environment mapping:
GL_EXT_texture_env_add, GL_ARB_texture_env_add, GL_ARB_texture_env_combine, 
GL_ARB_texture_env_crossbar, GL_ARB_texture_env_dot3, GL_ARB_texture_mirrored_repeat,
GL_ATI_envmap_bumpmap, GL_ATI_texture_env_combine3, GL_ATIX_texture_env_combine3,
GL_ATI_texture_mirror_once, GL_NV_texgen_reflection, GL_SGI_color_matrix, ...
This was no good.  Programmers had good ideas they couldn't get into hardware.  Programmers were frustrated trying to understand what the heck the hardware guys had created.  Hardware folks were tearing their hair out trying to support "just one more feature" with limited hardware.

The solution to the "too many shading methods to support in hardware" problem is just to support every possible shading method in hardware.  The easy way to do this is just make the shading hardware programmable.  

So, they did. 

Programmable Shaders are Very Simple in Practice

The graphics hardware now lets you do anything you want to incoming vertices and fragments.  Your "vertex shader" code literally gets control and figures out where an incoming glVertex should be shown onscreen, then your "fragment shader" figures out what color each pixel should be.

Here's what this looks like.  The following is C++ code, relying on the "makeProgramObject" shader-handling function listed below.  The vertex and fragment shaders are the strings in the middle.  These are very simple shaders, but they can get arbitrarily complicated.
void my_display(void) {
glClearColor(0,0,0,0); /* erase screen to black */

/* Set up programmable shaders */
static GLhandleARB prog=makeProgramObject(
"//GLSL Vertex shader\n"
"void main(void) {\n"
" gl_Position=gl_ModelViewProjectionMatrix * gl_Vertex;\n"
"//GLSL Fragment (pixel) shader\n"
"void main(void) {\n"
" gl_FragColor=vec4(1,0,0,1); /* that is, all pixels are red. */\n"

... glBegin, glVertex, etc. Ordinary drawing here runs with the above shaders! ...

glutSwapBuffers(); /* as usual... */
A few meta-observations first:
The stuff in strings is all "OpenGL Shading Language" (GLSL) code.  Just think of GLSL as plain old C++ with a nice set of 3D vector classes, and you're pretty darn close (I often use osl/vec4.h to copy and paste code between GLSL and C++!).
Data types in GLSL work exactly like in C/C++/Java/C#.  There are some beautiful builtin datatypes, though:
Bottom line: programmable shaders really are pretty easy to use.

Further Info

Try it!  Here's my simple PixAnvil fragment shader demo.

See also the GLSL cheat sheet (especially for builtin variables).

The official GLSL Language Specification isn't too bad--chapter 7 lists the builtin variables, chapter 8 the builtin functions.  OpenGL ES / GL 3.0 is similar, but they deprecated a bunch of the builtin variables from fixed-function GL.

If you're writing a C++ program, I built a GLSL-for-GPGPU library.