0

I'm having a bit of a structural problem with a shader of mine. Basically I want to be able to handle multiple lights of potentionally different types, but I'm unsure what the best way of implementing this would be. So far I've been using uniform blocks:

layout (std140) uniform LightSourceBlock
{
    int type;
    vec3 position;
    vec4 color;

    // Spotlights / Point Lights
    float dist;

    // Spotlights
    vec3 direction;
    float cutoffOuter;
    float cutoffInner;
    float attenuation;
} LightSources[12];

It works, but there are several problems with this:

  • A light can be one of 3 types (spotlight, point light, directional light), which require different attributes (Which aren't neccessarily required by all types)

  • Every light needs a sampler2DShadow (samplerCubeShadow for point lights), which can't be used in uniform blocks.

The way I'm doing it works, but surely there must be a better way of handling something like this? How is this usually done?

Silverlan
  • 2,783
  • 3
  • 31
  • 66
  • 1
    It is not like the texture image unit you bind your shadow map to is going to change every frame. You can make an aggregate structure of uniforms (e.g. array) and set the texture image unit once when you setup your program. Besides, GL only guarantees you have access to 16 texture image units per-shader stage. You are already using 12 if you intend to do 12 shadowed lights per-pass. That leaves 4 for specular,diffuse,normal,... It looks like your shader already requires a very strict sampler setup; hard coding the texture image units is the least of your worries. – Andon M. Coleman Jan 31 '14 at 16:16
  • Well, the 12 lights are actually per object (One object can be affected by max. 12 lights at a time, but there can be more than 12 lights in the scene), so I have to re-bind the shadowmaps every time before rendering each object. Is there a better way? – Silverlan Jan 31 '14 at 16:32
  • 1
    Short of bindless textures, which is an NV-only feature at the moment, not really. You will have to bind the shadow maps for the set of 12 lights you do per-pass. If you always agree that the shadow maps will be on something like texture image units 3-15, then you do not need to store the units as samplers in your UBO. – Andon M. Coleman Jan 31 '14 at 17:04
  • Thanks, but that still leaves me with one problem. I don't know in advance if a light is a pointlight(which use samplerCubeShadow) or a spotlight(sampler2DShadow) and I'd like to avoid having to use 2 arrays, since that would limit it to each 6 spotlights/pointlights. I guess that can't be helped? – Silverlan Jan 31 '14 at 19:11
  • 1
    I have never tried this, but I think you could have 2 arrays of 12 samplers. `sampler2DShadow spot [12];` and `samplerCubeShadow point [12];`. So long as no invocation of your shader uses more than 16 (or whatever your implementation's limit is) unique samplers, this should not violate anything. The thing is, when you start trying to write a single uber-shader that can handle every type of light, you would be better off unwrapping your cubemap into a 2D texture and using a special shadow lookup function depending on the type of light. CryENGINE works this way, 6 projectors into 1 2D texture. – Andon M. Coleman Jan 31 '14 at 19:19

0 Answers0