[Shader Library] Phong Shader with Multiple Lights (GLSL)



Shader Library - Phong lighting with multiple lights



More shaders are available here:Geeks3D Shader Library.

This is a lighting shader based on my old Phong model tutorial. This shader supports several lights (up to 8). There are two versions of the shader: the first one that works on both NVIDIA and ATI boards. The second one, more flexible, accepts the number of lights as an uniform variable. This uniform variable is used in a for() loop (in both vertex and pixel shaders). Currently, only NVIDIA GeForce and ATI Radeon HD 5000 support this construction. A bug in Catalyst prevents previous generation of Radeon (HD 4k, 3k, 2k) from executing the second shader.

You can download a GeeXLab demo to see the shader in real time:
Download Shader Lib - Lighting_Phong_Multiple_Lights_GLSL.zip

Unzip the archive somewhere. You can start the ATI/NVIDIA demo with Start_Demo_ATI_NVIDIA.bat and the NVIDIA and ATI HD 5000 demo with Start_Demo_NVIDIA_only.bat.

Some results:

  • Core 2 Duo E8400 / GeForce GTS 250 (Fw191.07) / WinXP SP2: 2800 FPS (800×600) and 800 FPS (1920×1200)
  • AMD X2 3800+ / Radeon HD 4850 (Cat9.9) / WinXP SP2: 2850 FPS (800×600) and 1350 FPS (1920×1080)

Shader Library - Phong lighting with multiple lights

First Shader desription (for NVIDIA and ATI)

Language: OpenGL 2 – GLSL

Type: Lighting

Inputs: none (the number of lights is hard coded: see NUM_LIGHTS define).

Ouputs: color buffer

Shader code:

[Vertex_Shader]
varying vec3 normal, eyeVec;
#define MAX_LIGHTS 8
#define NUM_LIGHTS 3
varying vec3 lightDir[MAX_LIGHTS];
void main()
{	
  gl_Position = ftransform();		
  normal = gl_NormalMatrix * gl_Normal;
  vec4 vVertex = gl_ModelViewMatrix * gl_Vertex;
  eyeVec = -vVertex.xyz;
  int i;
  for (i=0; i<NUM_LIGHTS; ++i)
    lightDir[i] = 
      vec3(gl_LightSource[i].position.xyz - vVertex.xyz);
}
[Pixel_Shader]
varying vec3 normal, eyeVec;
#define MAX_LIGHTS 8
#define NUM_LIGHTS 3
varying vec3 lightDir[MAX_LIGHTS];
void main (void)
{
  vec4 final_color = 
       gl_FrontLightModelProduct.sceneColor;
  vec3 N = normalize(normal);
  int i;
  for (i=0; i<NUM_LIGHTS; ++i)
  {  
    vec3 L = normalize(lightDir[i]);
    float lambertTerm = dot(N,L);
    if (lambertTerm > 0.0)
    {
      final_color += 
        gl_LightSource[i].diffuse * 
        gl_FrontMaterial.diffuse * 
        lambertTerm;	
      vec3 E = normalize(eyeVec);
      vec3 R = reflect(-L, N);
      float specular = pow(max(dot(R, E), 0.0), 
                           gl_FrontMaterial.shininess);
      final_color += 
        gl_LightSource[i].specular * 
        gl_FrontMaterial.specular * 
        specular;	
    }
  }
  gl_FragColor = final_color;			
}

Second Shader desription (for NVIDIA and ATI Radeon HD 5000 only)

Language: OpenGL 2 – GLSL

Type: Lighting

Inputs

  • numLights (int): number of lights. Max = 8.

Ouputs: color buffer

Shader code:

[Vertex_Shader]
varying vec3 normal, eyeVec;
#define MAX_LIGHTS 8
varying vec3 lightDir[MAX_LIGHTS];
uniform int numLights;
void main()
{	
  gl_Position = ftransform();		
  normal = gl_NormalMatrix * gl_Normal;
  vec4 vVertex = gl_ModelViewMatrix * gl_Vertex;
  eyeVec = -vVertex.xyz;
  int i;
  for (i=0; i<numLights; ++i)
    lightDir[i] = 
      vec3(gl_LightSource[i].position.xyz - vVertex.xyz);
}
[Pixel_Shader]
varying vec3 normal, eyeVec;
#define MAX_LIGHTS 8
varying vec3 lightDir[MAX_LIGHTS];
uniform int numLights;
void main (void)
{
  vec4 final_color = 
       gl_FrontLightModelProduct.sceneColor;
  vec3 N = normalize(normal);
  int i;
  for (i=0; i<numLights; ++i)
  {  
    vec3 L = normalize(lightDir[i]);
    float lambertTerm = dot(N,L);
    if (lambertTerm > 0.0)
    {
      final_color += 
        gl_LightSource[i].diffuse * 
        gl_FrontMaterial.diffuse * 
        lambertTerm;	
      vec3 E = normalize(eyeVec);
      vec3 R = reflect(-L, N);
      float specular = pow(max(dot(R, E), 0.0), 
                           gl_FrontMaterial.shininess);
      final_color += 
        gl_LightSource[i].specular * 
        gl_FrontMaterial.specular * 
        specular;	
    }
  }
  gl_FragColor = final_color;			
}

And for lazy people, the one light shader (works both on ATI and NVIDIA):

Shader code:

[Vertex_Shader]
varying vec3 normal, eyeVec, lightDir;
void main()
{	
  gl_Position = ftransform();		
  normal = gl_NormalMatrix * gl_Normal;
  vec4 vVertex = gl_ModelViewMatrix * gl_Vertex;
  eyeVec = -vVertex.xyz;
  lightDir = 
      vec3(gl_LightSource[0].position.xyz - vVertex.xyz);
}
[Pixel_Shader]
varying vec3 normal, eyeVec, lightDir;
void main (void)
{
  vec4 final_color = 
       gl_FrontLightModelProduct.sceneColor;
  vec3 N = normalize(normal);
  vec3 L = normalize(lightDir[0]);
  float lambertTerm = dot(N,L);
  if (lambertTerm > 0.0)
  {
    final_color += 
      gl_LightSource[0].diffuse * 
      gl_FrontMaterial.diffuse * 
      lambertTerm;	
    vec3 E = normalize(eyeVec);
    vec3 R = reflect(-L, N);
    float specular = pow(max(dot(R, E), 0.0), 
                         gl_FrontMaterial.shininess);
    final_color += 
      gl_LightSource[0].specular * 
      gl_FrontMaterial.specular * 
      specular;	
  }
  gl_FragColor = final_color;			
}



Geeks3D.com

↑ Grab this Headline Animator