Lighting Shaders
Shader programs that do not involve computing fragment color based on lighting or shading calculations are typically straightforward and relatively simple. For image filters, the fragment color is determined by the image data, modified by the filter. And drawing simple points requires setting a simple color to tell OpenGL what color to use when drawing the points.
However, when a shader is performing lighting calculations rather than drawing an image, the shader program replaces the fixed, OpenGL lighting calculations. Your shader program code will need to define lighting and shading effects. In general, this is a fairly complex task, but there are tools available to make it a bit easier.
Note
The code in the following example was created with a tool called ShaderGen, by 3Dlabs (http://www.3dlabs.com). It is beyond the scope of this documentation to describe such third party tools. However, an internet search will likely provide several options that allow you to define and adjust lighting parameters and produce usable shader code output.
Beyond defining the characteristics of lights in GLSL code, you need to understand how lights defined in IDL relate to the OpenGL light table.
IDL Lights and the OpenGL Light Table
In IDL there is a limit of 8 active IDLgrLight objects, which you define by their position, direction, color, and other parameters. OpenGL passes these light definitions to the shader program via a pre-defined GLSL array variable called gl_LightSource. The shader program then looks up the light definitions in the table and performs the required lighting calculations. The key is determining which IDL light corresponds to a light entry in the gl_LightSource table.
The IDLgrLight object LIGHT_INDEX property provides a means of tying a particular IDLgrLight object to an element of the gl_LightSource table. When you define a light, you also set the LIGHT_INDEX property to a value between 0 and 7, inclusive, without duplicating a value in any of the lights. You can then pass these indices to the shader program in uniform variables, or simply hard-code it in the shader program.
For example the following code creates a light and tells OpenGL to put the definition for this light in entry 4 of the light source table:
oLight = OBJ_NEW('IDLgrLight', TYPE=1, LOCATION=[200,200,500], $
COLOR=[255,255,255], INTENSITY=0.8, LIGHT_INDEX=4)
The shader program then expects to see the definition for this light in entry 4 of the table. Here some shader program code fetches the light characteristics:
Ambient += gl_LightSource[4].ambient * attenuation; Diffuse += gl_LightSource[4].diffuse * nDotVP * attenuation; Specular += gl_LightSource[4].specular * pf * attenuation;Note
In some shader programs, the light needs to be identified by a single integer value (such as4) instead of by a light table entry (gl_LightSource[4]). In such a case, you can define a uniform variable that contains the light index value and pass this to the shader program. The following example uses this method, defining a uniform variable named DirectionalLightIndex with a value of 4 and passing it to the shader program.
Ambient Lights
An ambient light is a bit different from the other lights. IDL does not use a light source to define an ambient light, and an ambient light does not count toward the limit of 8 active lights. Instead, IDL sets the ambient portion of the OpenGL light model state to the desired ambient light color and intensity. (If a light is not defined with a TYPE setting of positional, directional, or spotlight, the light will be considered to be an ambient light by default.) In a shader program, you would add in the ambient light contribution as follows:
Ambient = gl_LightModel.ambient; // Use IDL's ambient lightNote
See "IDLgrLight" (IDL Reference Guide) for additional information about ambient lights.