[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;			
}


2 thoughts on “[Shader Library] Phong Shader with Multiple Lights (GLSL)”

  1. Master R.

    Hello, i just wanted to say that this is a wonderful shader! but also i would like to know, how to add a attenuation? as shown in here:
    http://www.ozone3d.net/tutorials/glsl_lighting_phong_p4.php

    i have tried to implement this myself but some how it just overbrights my scene.

    Could you please update the shader with the attenuation and send it to me via email? Thanks!

  2. P

    I have little actual idea but a guess instead. Could the reason behind the problem be that your objects are very close to you? If you won’t clip distance values under, say, 1.0f to the 1.0f, they’ll appear being extremely brightly lit. Just a guess though, and it’s been two years since your comment.. but hope this will help you or at least someone.

Comments are closed.