Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 7 of 7

Thread: GLSL multiple lights

  1. #1
    Junior Member Newbie
    Join Date
    Feb 2008
    Location
    Linköping, Sweden
    Posts
    7

    GLSL multiple lights

    Hi, does anyone know how to implement multiple lights in GLSL?

    I have implemented the following code:
    vertex shader:
    Code :
    varying vec3 normal, lightDir;
    varying vec4 diffuse;
    void main()
    {
      gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;
     
      vec3 transformedNormal = gl_NormalMatrix * gl_Normal;
     
      normal = gl_NormalMatrix * gl_Normal;
     
      if(vec3(gl_LightSource[0].position) != vec3(0.0, 0.0, 0.0)) {
        lightDir = vec3(gl_LightSource[0].position);
        diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
      }
     
    }

    fragment shader:
    Code :
    varying vec3 normal, lightDir;
    varying vec4 diffuse;
    void main()
    { 
      vec4 color;
      float dotProduct;  
     
      dotProduct = dot(normal, lightDir);
     
      color = dotProduct * diffuse;
     
      gl_FragColor = color;
    }

    So now I want to add 3 other lights, gl_LightSource[1], gl_LightSource[2] and gl_LightSource[3] which comes from different directions and have different colors and are defined in the .c file. How do I do this? You turn the lights on and off with the F1, F2, F3 and F4 keys and my if statement is supposed to check if the light is activated or not. I managed to get all the lights to work with a for statement before the if statement but the lights couldn't be activated at the same time with that solution, just one at a time. I want to be able to have blue light on one side of an object and red light on the other side, for an example.

  2. #2
    Super Moderator Frequent Contributor Groovounet's Avatar
    Join Date
    Jul 2004
    Posts
    936

    Re: GLSL multiple lights

    You have several solution for your problem and that where it starts to become interesting. The easy way is to use a uniform variable to specific the light count... However, this fast to code solution wrong work on other hardware than GeForce 8 I guest.

  3. #3
    Junior Member Regular Contributor oc2k1's Avatar
    Join Date
    Jan 2007
    Location
    germany
    Posts
    171

    Re: GLSL multiple lights

    General a for loop can be use to iterate over the lights. But there is a limitation with shader model 3.0 (and below) so that it isn't possible to index uniform variables with a dynamic variable in fragment shaders.

    Code :
    for (int light= 0; light < MAXLIGHTS; light++){
        gl_FragColor += gl_LightSource[light].diffuse;
        }
    This code will run on a shader model 4.0 card without limitations. MAXLIGHTS can be a uniform or a constant. On a shader model 3.0 card. It is not possible. In that case it's recommend to compile a own shader for each number of lights, by replacing MAXLIGHTS by a constant (can be done with with #define)

    If many lights should be handled by a fragment shader it is recommend to calculate the lighting in model view space, to keep the number of varyings low.

  4. #4
    Junior Member Newbie
    Join Date
    Feb 2008
    Location
    Linköping, Sweden
    Posts
    7

    Re: GLSL multiple lights

    What about the light direction and the dot product? Maybe I don't need them, I don't know.

    I've tried this code before:
    Code :
    for(int i = 0; i <= 3; i++) {
      if(vec3(gl_LightSource[i].position) != vec3(0.0, 0.0, 0.0)) {
        lightDir += vec3(gl_LightSource[i].position);
        diffuse += gl_FrontMaterial.diffuse * gl_LightSource[i].diffuse;
      }
    }

    But the result I got from that was that when I activated the blue and red lights for an example, I got a purple light with a position between the positions the two lights was supposed to have. So I still only got one light at a time.

  5. #5
    Advanced Member Frequent Contributor
    Join Date
    May 2005
    Location
    Prague, Czech Republic
    Posts
    924

    Re: GLSL multiple lights

    You must sum final lighting contributions, direction and diffuse properties of the lights must remain independent.

    For directional lights which you are using, you can simply access the gl_LightSource[0] uniforms from the fragment shader to get entire direction so there is no need to send it trough varying.

    For point lights you can use vertex shader to send fragment position in any suitable space to the fragment shader and calculate the directions there.

  6. #6
    Junior Member Newbie
    Join Date
    Feb 2008
    Location
    Linköping, Sweden
    Posts
    7

    Re: GLSL multiple lights

    Solved it! Made a function for each light.

    vertex shader
    Code :
    varying vec3 normal;
    void main()
    {
      gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;
     
      normal = gl_NormalMatrix * gl_Normal;
     
    }

    fragment shader
    Code :
    varying vec3 normal;
     
    vec4 light0 ()
    {
      vec4 color;
     
      vec3 lightDir = vec3(gl_LightSource[0].position); 
     
      vec4 ambient = gl_LightSource[0].ambient * gl_FrontMaterial.ambient;
     
      vec4 diffuse = gl_LightSource[0].diffuse * max(dot(normal,lightDir),0.0) * gl_FrontMaterial.diffuse;
     
      color = ambient + diffuse;
     
      return color;
    }
     
    vec4 light1 ()
    {
      vec4 color;
     
      vec3 lightDir = vec3(gl_LightSource[1].position); 
     
      vec4 ambient = gl_LightSource[1].ambient * gl_FrontMaterial.ambient;
     
      vec4 diffuse = gl_LightSource[1].diffuse * max(dot(normal,lightDir),0.0) * gl_FrontMaterial.diffuse;
     
      color = ambient + diffuse;
     
      return color;
    }
     
    vec4 light2 ()
    {
      vec4 color;
     
      vec3 lightDir = vec3(gl_LightSource[2].position); 
     
      vec4 ambient = gl_LightSource[2].ambient * gl_FrontMaterial.ambient;
     
      vec4 diffuse = gl_LightSource[2].diffuse * max(dot(normal,lightDir),0.0) * gl_FrontMaterial.diffuse;
     
      color = ambient + diffuse;
     
      return color;
    }
     
    vec4 light3 ()
    {
      vec4 color;
     
      vec3 lightDir = vec3(gl_LightSource[3].position); 
     
      vec4 ambient = gl_LightSource[3].ambient * gl_FrontMaterial.ambient;
     
      vec4 diffuse = gl_LightSource[3].diffuse * max(dot(normal,lightDir),0.0) * gl_FrontMaterial.diffuse;
     
      color = ambient + diffuse;
     
      return color;
    } 
     
    void main()
    { 
      vec4 light;
     
      if(vec3(gl_LightSource[0].position) != vec3(0.0, 0.0, 0.0))
        light += light0();
      if(vec3(gl_LightSource[1].position) != vec3(0.0, 0.0, 0.0))
        light += light1();
      if(vec3(gl_LightSource[2].position) != vec3(0.0, 0.0, 0.0))
        light += light2();
      if(vec3(gl_LightSource[3].position) != vec3(0.0, 0.0, 0.0))
        light += light3();
     
      gl_FragColor = light;
    }

    Thanks for your help though.

  7. #7
    Junior Member Regular Contributor oc2k1's Avatar
    Join Date
    Jan 2007
    Location
    germany
    Posts
    171

    Re: GLSL multiple lights

    That isn't the best solution, use a integer as argument to set the lightnumber for the light function.
    The if statement isn't a good solution too, it would be faster to use a own shader for each number of lights.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •