Limiting light calculations

Started by
4 comments, last by MJP 8 years, 2 months ago
Hi everyone,

Is there a way to limit the influence of lights in a scene to a particular distance. For example, if a lamp is in one corner of the room, the amount of light that reaches the other corner after taking attenuation into account is very insignificant that I may as well have left it uncalculated.

My first idea is to calculate the fragment's world space distance from light in pixel shader and then proceed to evaluate the lighting equation based on that distance. But this requires 'if' statement in pixel shader. I was always advised to avoid dynamic branching in pixel shader. Any ideas?
Advertisement
I added a range dependent falloff to ensure, that a light source only lit a limited, spherical area.

intensity *= max(0,1 - square_distance_to_light/(max_distance*max_distance))

I was always advised to avoid dynamic branching in pixel shader.


You should follow this advice if you're working on a GPU from 2005. If you're working on one from the last 10 years...not so much. On a modern GPU I would say that there's two main things you should be aware of with dynamic branches and loops:

1. Shaders will follow the worst case within a warp or wavefront. For a pixel shader, this means groups of 32-64 pixels that are (usually) close together in screen space. What this means is that if you have an if statement where the condition evaluates false to 31 pixels but true for one pixel in the 32-thread warp, then they're all to execute what's inside the if statement. This can be especially bad if you have an else clause, since you can end up with your shader executing both the "if" as well as the "else" part of your branch! For loops it's similar: the shader will keep executing the loop until all threads have hit the termination condition. Note that if you're branching or looping on something from a constant buffer, then you don't need to worry about any of this. For that case every single pixel will take the same path, so there's no coherency issue.

2. Watch out for lots of nested flow control. Doing this can start to add overhead from the actual flow control instructions (comparisons, jumps, etc.), and can cause the compiler to use a lot of general purpose registers.

For the case you're talking about, a dynamic branch is totally appropriate and is likely to give you a performance increase. The branch should be fairly coherent in screen space, so you should get lots of warps/wavefronts that can skip what's inside of the branch. For an even more optimal approach, look into deferred or clustered techniques.
You can also do cheap squared length tests to check your (sub)objects with your light sources. Then store the ones that affect the object and only process these when rendering that object. Of course you can play with margins there also (bit lower or higher then the distance between them).

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

I was always advised to avoid dynamic branching in pixel shader.


1. Shaders will follow the worst case within a warp or wavefront. For a pixel shader, this means groups of 32-64 pixels that are (usually) close together in screen space. What this means is that if you have an if statement where the condition evaluates false to 31 pixels but true for one pixel in the 32-thread warp, then they're all to execute what's inside the if statement. This can be especially bad if you have an else clause, since you can end up with your shader executing both the "if" as well as the "else" part of your branch!

So each of the 32 pixels will execute both the if/else cases?

But the pixel will still only contain the result of the "correct" branch I suppose? So no pixels will end up being shaded wrongly due to branching.

I was always advised to avoid dynamic branching in pixel shader.


1. Shaders will follow the worst case within a warp or wavefront. For a pixel shader, this means groups of 32-64 pixels that are (usually) close together in screen space. What this means is that if you have an if statement where the condition evaluates false to 31 pixels but true for one pixel in the 32-thread warp, then they're all to execute what's inside the if statement. This can be especially bad if you have an else clause, since you can end up with your shader executing both the "if" as well as the "else" part of your branch!


So each of the 32 pixels will execute both the if/else cases?
But the pixel will still only contain the result of the "correct" branch I suppose? So no pixels will end up being shaded wrongly due to branching.


Yes, that's right. The results will look correct, since GPU's are able to mask certain threads based on the branch result. However you will pay the cost of executing both sides of the branch, unless all threads in the warp/wavefront take the same path.

This topic is closed to new replies.

Advertisement