Sign in to follow this  

Deferred,glitch rendering point lights.

Recommended Posts

Hello!

 

The other day I´ve been improving my deferred renderer for the university adding CookTorrance and some other pbr fanciness. I saw a glitch with the point lights. When I´m inside of the point light, the walls on the other side of the room get illuminated (which should be impossible). Lets see a picture.

 

http://i.imgur.com/HExEc5k.jpg

 

The point lights are going around the Sponza atrium and when they reach where the camera stands, I can see the walls on the other side get affected by the light. I´m having a similar problem with the curtains, as they are getting illuminated from behind.

 

I´m rendering the light volume with glCullFace(GL_FRONT);.

 

Any ideas?

As always. thanks!

 

 

 

Share this post


Link to post
Share on other sites

If you are calculating light intensity as:
intensity = 1 - ( dist(pos, light.pos) / light.range )

 

You'll start getting negative results once dist exceeds 'range', depending on how the rest of your math works out, this can cause artifacts.

You should clamp/saturate the result:
intensity = clamp( 1 - ( dist(pos, light.pos) / light.range ), 0, 1 );

 

Although, the discard solution may be more efficient, as you avoid hitting the framebuffer entirely instead of blending in a zero-strength light.
 

Depending on the precision of your render target, it may be best to do the discard last, and choose a minimum light strength that you know the render target will floor to zero, eg:
if( intensity < 1/255 ) { discard; }

 

You could also take this one step further and take into account the light color as well, since its RGB values are likely less than 1.

vec3 outColor = lightColor.rgb*intensity;

if( max( outColor.r, max( outColor.g, outColor.b ) ) < 1/255 ) { discard; }

Edited by ShaneYCG

Share this post


Link to post
Share on other sites

If you are calculating light intensity as:
intensity = 1 - ( dist(pos, light.pos) / light.range )

 

You'll start getting negative results once dist exceeds 'range', depending on how the rest of your math works out, this can cause artifacts.

You should clamp/saturate the result:
intensity = clamp( 1 - ( dist(pos, light.pos) / light.range ), 0, 1 );

 

Although, the discard solution may be more efficient, as you avoid hitting the framebuffer entirely instead of blending in a zero-strength light.
 

Depending on the precision of your render target, it may be best to do the discard last, and choose a minimum light strength that you know the render target will floor to zero, eg:
if( intensity < 1/255 ) { discard; }

 

You could also take this one step further and take into account the light color as well, since its RGB values are likely less than 1.

vec3 outColor = lightColor.rgb*intensity;

if( max( outColor.r, max( outColor.g, outColor.b ) ) < 1/255 ) { discard; }

 

I will try it an see if I can see any diferences.

Thanks.

Share this post


Link to post
Share on other sites

If you're going for PBR, doing:

intensity = clamp( 1 - ( dist(pos, light.pos) / light.range ), 0, 1 );

is probably not a good idea, the actual attenuation of light in vacuum is proportionate to squared inverse of distance so the better way of calculating intensity is:
i: The intensity of light at 1 meter.

 vec3 l = light.pos - pos;
intensity = i/(dot l,l);

where you probably have calculated l for lighting, and its size as well for normalizing, so optimize the code however you'd like.

This makes the light range quite redundant, however for an early out you might want to use it to discard the fragment which isn't that much of a brilliant idea, since the branching how ever modern the GPU is not a good idea on GPU, moreover you might need even the smallest amount of light reached to a pixel for later use on some post processing effects on HDR rendering. In conclusion I do not suggest any light omitting, but you can do it as below:

i: The intensity of light at 1 meter.

light_range = sqrt(255 * i);

On the shader:

if (length(l)<light_range)
     discard;
Edited by IYP

Share this post


Link to post
Share on other sites

 

If you're going for PBR, doing:

intensity = clamp( 1 - ( dist(pos, light.pos) / light.range ), 0, 1 );

is probably not a good idea, the actual attenuation of light in vacuum is proportionate to squared inverse of distance so the better way of calculating intensity is:
i: The intensity of light at 1 meter.

 vec3 l = light.pos - pos;
intensity = i/(dot l,l);

where you probably have calculated l for lighting, and its size as well for normalizing, so optimize the code however you'd like.

This makes the light range quite redundant, however for an early out you might want to use it to discard the fragment which isn't that much of a brilliant idea, since the branching how ever modern the GPU is not a good idea on GPU, moreover you might need even the smallest amount of light reached to a pixel for later use on some post processing effects on HDR rendering. In conclusion I do not suggest any light omitting, but you can do it as below:

i: The intensity of light at 1 meter.

light_range = sqrt(255 * i);

On the shader:

if (length(l)<light_range)
     discard;

 

Branching can be OK as long as it is mostly coherent within the warp/half warp, and for this they would be mostly coherent except for the edge of the light's effectiveness where both if/else may need to be evaluated. For deferred framebuffer b/w can be a significant bottleneck, so the branch may be worthwhile.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this