Multiple Dynamic Light Sources in GL3

Hey you guys!

Does anyone here have concrete experience with light management in GL3 using GLSL 1.5+? I’m currently going nuts trying to figure out the most elegant and efficent way to pass information about multiple light sources to a corresponding shader.

Here are my approaches:

Approach A:

For each type of light Use an array of uniform block with corresponding uniform buffers like:


uniform DLight
{
  vec3 Direction;
} D_Lights[x];

The drawback here is, since I’m working on a Radeon 4870 which doesn’t support Shader Model 5, indexing with a non-const expression in a loop isn’t supported:


for(int i = 0; i < dlights.lenght(); ++i)
{
   vec3 dir = D_Lights[i].Direction;
}

This will fail, making it necessary to index the instances explicitly which is tedious.

Approach B:

Write all information about the lights of a type in to a corresponding texture buffer. The buffer has a distinct layout and allows for texel fetching all the information of all light sources of a type by using the correct offsets.

Two major caveats of this approach are that fetching a matrix cannot be done in a single call but has to be done with 4 separate texel fetches and the correct offset and the second is that the shaders will unnecessarily grow only because of the texel fetching code. It is also much more prone to developer mistakes.

An advantage is that it is the closest thing to dynamic arrays in GLSL due to the ability to fetch the size of the texture. Since the size of data for each light source is know, computing the total amount of lights in a buffer is trivial.

Approach C:

Only use one single directional light, e.g. the sun, and use deferred shading for the rest.

One major flaw of A and B is that there seems to be no way whatsoever to elegantly associate a shadow map with the light source.

A boolean within the uniform block or the texture buffer could be used to indicate how many light sources have a shadow map. Using a counter which increments with every light using a depth buffer und the counter could then be used to index a uniform array of samplers or simply a texture array.

What do you guys think? Am I totally off track? Missing something? Thinking too complicated?

Thanks everyone!

Thomas

For each type of light Use an array of uniform block with corresponding uniform buffers like:

Why are you doing that? Why not have a uniform block that contains an array? Indexing uniform arrays has no restrictions, so you can index them however you want.

It’s very simple:


struct PerLight
{
  vec3 direction;
}

uniform DLight
{
  PerLight lights[x];
};

This way, you only have one uniform block to worry about.

If you need a uniform block per light, you can put all your lighting code in a function (say, lightingModel), and pass the block parameters to it. While you’ll still need to define a bunch of nearly identical uniform blocks ( uniform light# { uniforms } lightSource#; ) and call lightingModel multiple times with these block parameters (lightingModel(lightSource#.diff,…)), this at least keeps your lighting code to one copy.

You don’t need to use deferred lighting for shadows if you have a small number of shadow-casting lights, which all use a similar shadowing technique. This works well with a depth-only pass done first to eliminate occluded pixels. GL3 hardware has at least 16 texture units, which should be enough units for shadowmaps and other material textures. If your lights vary in shadow technique, it’s likely easier and faster to use a deferred lighting scheme with a shader per shadowing technique.

Thanks you two and excuse my delayed response.

I’ll stick with Alfonse on this one - either I’m going blind or something, but the array nested inside the block completely slipped through my fingers… :eek:

I guess I’ll post some shots later.