OpenGL Shading Language Independent Study
Scott Douglas

Description
People
Deliverables
Links
Thoughts

Description

This project contains two main parts: research and implementation. The first 3-4 weeks will be researching the basics and capabilities of the OpenGL Shading Language. The rest of the time will consist of writing shaders for a game that is currently called "The Racing Game". Once this game is finished, we plan on submitting it to the IGF competition. The following shaders are needed so far:
  • Per pixel bump map lighting with support for multiple lights
  • Same as above with cube map reflection
  • Parallax Mapping
  • Smoke Shader
  • Fire Shader
The deliverables will include the shaders themselves as well as a website of documentation on the shaders.

People

Scott Douglas (Student)
scott ~NOTAT~ scottdouglas.net
http://www.scottdouglas.net

Joe Geigel (Faculty Sponser)
jmg ~NOTAT~ cs.rit.edu
http://www.cs.rit.edu/~jmg

Deliverables

  • Per pixel bump map lighting with support for multiple lights:


    Project Directory

    The first image shows the torus with only it's ambient color. In the second image, it is lit by two lights. The third image adds the effect of the bump map. The fourth image textures the object.

    Project Download - bump.zip

  • Same as above with cube map reflection


    Project Directory

    This shader adds an environment map reflective component to the torus.

    Project Download - bumpcubemap.zip

  • Fire Shader



    Project Directory
    Project Download - fire.zip

  • Smoke Shader



    Project Directory
    Project Download - smoke.zip

  • Parallax Mapping



    Project Directory

    The first image shows the cube with only the texture map. Notice how flat the iamge looks. The second image adds the parallax mapping. For a great technical description of parallax mapping, read Parallax Mapping with Offset Limiting. Basically, parallax mapping shifts texture coordinates to simulate seeing different sides of surfaces. Note how you can see the left side of the extruded face on one side of the cube, and the right side of the extruded face on the other side of the cube. Since this technique only shifts texture coordinates, you can then use the new texture coordinates in other look ups to add additional effects. Parallax mapping doesn't deal with lighting in any way. It can be combined with bump mapping to light the new surfaces it shows with the proper normals. The third image shows bump mapping only. Notice how well lit the image looks. The fourth image combines both bump mapping and parallax mapping. This is a BIG improvement over the original textured cube. The cube is only 12 polygons. All the detail is from the bump, texture, and height maps. The technique is especially apparent when moving around the object.

    Project Download - parallax.zip

  • Website - You're here. :)

Links

Thoughts

GLSL is apparently pronounced "GL-Slang". I don't like this, and will keep calling it "G-L-S-L".

Part of the independent study was research. I've included a links section to websites that I've found particularly good in one way or another. Instead of providing a summary of the basics of GLSL, I'll leave it up to the websites. Why reinvent the wheel? I'll try to keep these "thoughts" to my own observations and experiences.

I found the process of developing shaders somewhat tedious. I originally tried to develop in Visual Studio using a C++ program to load the shaders. This gave ultimate control over what data as available to the shader, but debugging was difficult. There was no syntax highlighting to prevent common typing errors.

I then turned to RenderMonkey, which I had seen at SIGGRAPH. RenderMonkey seemed like a breath of fresh air. It added the ability to easily add variables to expose to the shader. It updated the shader in real-time. Colors could be tweaked on the fly. It had syntax highlighting! RenderMonkey is not without it's shortcomings. The UI is non-intuitive at times. I wanted to save my fragment / vertex shaders to files. When you click on "File", the only save option is to save the workspace. Additionally, there is no "Find" feature off the main toolbar. Eventually I found these features by accidently right clicking on the actual vertex program. I still can't find a "Select All" option. There is a newer version of RenderMonkey than the one I'm using. Perhaps these minor (but important!) oversights are remedied.

GLSL has built in variables for querying OpenGL state. One is gl_LightSource[]. This array contains parameters for all the lights in OpenGL. When attempting to use this in a generic way, RenderMonkey croaks. Apparently you must define array sizes before indexing by a variable. When you attempt to do this, the compiler complains that gl_LightSource is a reserved keyword. You can't win. I briefly attempted using Shader Designer. It had the same problem. In RenderMonkey, there are no options dealing with lighting. Shader Designer at least allows you to set the light in the scene. Although, I couldn't find an option to add another light. I ended up going back to RenderMonkey and adding variables for the light parameters I needed another way. This makes it MUCH less generic, but there was no choice. Lighting support needs some definite attention in the shader development world. It doesn't seem like it would be that hard to have a dialog box where you can tweak the lighting settings.

The tradeoff for using a shader editor is lack of control. You have less control over what and how information is passed into your shader. For one of the shaders, I needed tangent values. Fortunately, RenderMonkey has a way to pass tangents in. The problem is, the documentation for it is poor at best. Apparently you have to add the tangent data in a dialog for "Stream Mapping". This isn't so bad. The next step, which is key, took me forever to find. In order to then get at that data, you need to declare an attribute called rm_Tangent. The only place this is shown in the documentation is in the "What's New" section, which I skipped since I had never used a previous verison. The "Stream Mapping" section skims over the topic. A problem arises when you need data that RenderMonkey isn't set up to provide. At this point, you have no choice but to stop using the editor. This is frustrating.

Overall, I would still recommend using RenderMonkey. It made many tasks much easier. To view the shaders in all their glory, you'll need to download RenderMonkey. A link is provided in the links section. The .rfx files in the project directories are RenderMonkey files.

When compiling some example GLSL code off the web, I noticed that there are some vast differences in GLSL support. A lot of code was no where near compiling. Some used functions that appear to be nVidia specific. Adhering to standards would be helpful.

As you can see from the smoke and fire shaders, shaders are bad at particles. In my opinion, shaders should NEVER be used for particle systems. After trying to implement it, I realized the problem. Shaders have no ability to write back state. Particles systems are nothing but changing state. If you're going to change the state in the application, then you now no longer save anything by using a shader. All it would do is color the pixel.

While writing these shaders, I was dismayed at the lack of noise in shaders. The "Orange Book" mentions some noise functions, but my compiler wouldn't recognize any of them. There's not even a random function that I could find. This seriously limits the abilities of the shader to mimic natural behavior (and to create particle systems properly). I've seen some shaders that actually implement Perlin noise in the shader. The few I've seen have been hacks that do texture lookups. Noise should be a part of the language.

GLSL is a powerful tool in graphics development. Replacing the fixed function pipeline with a programmable pipeline opens up many options. GLSL still has some growing up to do.