Adding Lighting and Shading to a Surface

This example displays an IDLgrSurface, and uses the vertex shader to displace part of it up and down in an animation sequence. It also changes the color of the displaced part slightly for additional emphasis. An ambient light and a positional light illuminate the surface.

Example Code
See shader_lightsurf_doc.pro, located in the examples/doc/shaders subdirectory of the IDL distribution, for the complete, working example. Run the example procedure by entering shader_lightsurf_doc at the IDL command prompt or view the file in an IDL Editor window by entering .EDIT shader_lightsurf_doc.pro.

First create the surface:

; Generate surface data and create surface object. 
surfdata = BESELJ(SHIFT(dist(100), 50, 50) / 2,0) * 40 
oSurface = OBJ_NEW('IDLgrSurface', surfdata, STYLE=2, 
COLOR=[200,200,40]) 
 
; Create model for the visibile surface and rotate angle 
; for good viewing. 
oModel = OBJ_NEW('IDLgrModel') 
oModel->Add, oSurface 
oModel->Translate, -50, -50, 0 
oModel->Rotate, [0,0,1], -30 
oModel->Rotate, [1,0,0], -60 
oModel->Translate, 50, 50, 0 

Then define the ambient and positional lights. The directional light has an arbitrary light index value (4 in this example) in order to identify it in the shader program.

oLightModel = OBJ_NEW('IDLgrModel') 
oLightModel->Add, OBJ_NEW('IDLgrLight', TYPE=0, $ 
  COLOR=[100, 50, 40]) 
oLightModel->Add, OBJ_NEW('IDLgrLight', TYPE=1, 
   LOCATION=[200,200,500], $ 
   COLOR=[255,255,255], INTENSITY=0.8, LIGHT_INDEX=4) 

Uniform and Attribute Variables for Lighting Shader

The IDL application (shader_lightsurf_doc.pro) creates and passes two uniform variables and an attribute variable containing per-vertex information to the shader program.

Hardware Shader Program for Lighting Shader

The vertex shader program for this example was largely generated by 3Dlabs' ShaderGen program. Only a small amount of code needed to be added or modified to make the generated code work with the example IDL application. See the code comments for details.

Example Code
See lightSurfVert.txt, located in the examples/doc/shaders subdirectory of the IDL distribution, for the complete, working example.

The fragment shader program (lightsurf.frag) is very simple:

void main() { 
gl_FragColor = gl_Color; 
} 

Assign Lighting Shader Program to Shader Object

The vertex shader program is rather long and complex, so it is stored in an external file, as is the fragment shader program. Associate the shader program components with the IDLgrShader object using the VERTEX_PROGRAM_FILE and FRAGMENT_PROGRAM_FILE properties.

; Access shader program files. 
vertexFile=FILEPATH('lightSurfVert.txt', $ 
   SUBDIRECTORY=['examples','doc', 'shaders']) 
fragmentFile=FILEPATH('lightSurfFrag.txt', $ 
   SUBDIRECTORY=['examples','doc', 'shaders']) 
    
; Create shader and associate vertex and fragment programs. 
oShader = OBJ_NEW('IDLgrShader') 
oShader->SetProperty, VERTEX_PROGRAM_FILENAME=vertexFile, $ 
   FRAGMENT_PROGRAM_FILENAME=fragmentFile 
 
; Associate shader with the surface. You can comment out  
; this line to run without the shader program. 
oSurface->SetProperty, SHADER=oShader 

With the appropriate display objects and a FOR loop to increment the uniform variable Time, you can visualize the results of applying the shader program lighting calculations to the surface. A detail of the surface during program execution appears in the following figure.

Figure 14-9: Lighting Calculations Applied to Surface Displacement

shader_lightsurf.gif