Shading with multiple positional lights

When shading with multiple light sources, we need to evaluate the shading equation for each light and sum the results to determine the total light intensity reflected by a surface location. The natural choice is to create uniform arrays to store the position and intensity of each light. We'll use an array of structures so that we can store the values for multiple lights within a single uniform variable.

The following figure shows a "pig" mesh rendered with five light sources of different colors. Note the multiple specular highlights.

Shading with multiple positional lights

Getting ready

Set up your OpenGL program with the vertex position in attribute location zero, and the normal in location one.

How to do it...

To create a shader program that renders using the ADS (Phong) shading model with multiple light sources, use the following steps:

  1. Use the following vertex shader:
    layout (location = 0) in vec3 VertexPosition;
    layout (location = 1) in vec3 VertexNormal;
    
    out vec3 Color;
    
    struct LightInfo {
      vec4 Position;  // Light position in eye coords.
      vec3 Intensity; // Light intensity
    };
    uniform LightInfo lights[5];
    
    // Material parameters
    uniform vec3 Kd;            // Diffuse reflectivity
    uniform vec3 Ka;            // Ambient reflectivity
    uniform vec3 Ks;            // Specular reflectivity
    uniform float Shininess;    // Specular shininess factor
    
    uniform mat4 ModelViewMatrix;
    uniform mat3 NormalMatrix;
    uniform mat4 MVP;
    
    vec3 ads( int lightIndex, vec4 position, vec3 norm )
    {
      vec3 s = normalize( vec3(lights[lightIndex].Position – 
                               position) );
      vec3 v = normalize(vec3(-position));
      vec3 r = reflect( -s, norm );
      vec3 I = lights[lightIndex].Intensity;
      return
            I * ( Ka +
            Kd * max( dot(s, norm), 0.0 ) +
            Ks * pow( max( dot(r,v), 0.0 ), Shininess ) );
    }
    void main()
    {
      vec3 eyeNorm = normalize( NormalMatrix * VertexNormal);
      vec4 eyePosition = ModelViewMatrix * 
                         vec4(VertexPosition,1.0);
    
      // Evaluate the lighting equation for each light
      Color = vec3(0.0);
      for( int i = 0; i < 5; i++ )
        Color += ads( i, eyePosition, eyeNorm );
    
      gl_Position = MVP * vec4(VertexPosition,1.0);
    }
  2. Use the following simple fragment shader:
    in vec3 Color;
    
    layout( location = 0 ) out vec4 FragColor;
    
    void main() {
      FragColor = vec4(Color, 1.0);
    }
  3. In the OpenGL application, set the values for the lights array in the vertex shader. For each light, use something similar to the following code. This example uses the C++ shader program class (prog is a GLSLProgram object).
    prog.setUniform("lights[0].Intensity",
                    vec3(0.0f,0.8f,0.8f) );
    prog.setUniform("lights[0].Position", position );

    Update the array index as appropriate for each light.

How it works...

Within the vertex shader, the lighting parameters are stored in the uniform array lights. Each element of the array is a struct of type LightInfo. This example uses five lights. The light intensity is stored in the Intensity field, and the position in eye coordinates is stored in the Position field.

The rest of the uniform variables are essentially the same as in the ADS (ambient, diffuse, and specular) shader presented in Chapter 2, The Basics of GLSL Shaders.

The ads function is responsible for computing the shading equation for a given light source. The index of the light is provided as the first parameter lightIndex. The equation is computed based on the values in the lights array at that index.

In the main function, a for loop is used to compute the shading equation for each light, and the results are summed into the shader output variable Color.

The fragment shader simply applies the interpolated color to the fragment.

See also

  • The Implementing per-vertex ambient, diffuse, and specular (ADS) shading recipe in Chapter 2, The Basics of GLSL shaders
  • The Shading with a directional light source recipe
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.217.203.172