Deferred Shading: point light and bounding volume

Started by
30 comments, last by Pthalicus 13 years ago
I'm implementing a simple deferred shading demo in DirectX11, taking inspiration from some know papers and this tutorial made for XNA.
Below you can see three screanshot of the demo, taken in three different modes, and the problem that I've is on the third mode:
1) Standard rendering
2) Deferred rendering, for each light a full screen pass is made. In this mode I obtains a frame rate more slow than standard rendering.

mgdexample1020110507235.th.png

3) Deferred rendering, for each light I define a bounding volume (sphere), and I computes the illumination only on the geometry that is in this volume. But the result is horrible.

mgdexample1020110507235.th.png

So the question is: where is the problem? What I'm doing is wrong?
Thanks.
Advertisement
You'll need to apply an attenuation to the lighting that takes into consideration the size of the bounding sphere.
So the lighting won't appear to be "clipped", it will gradually fade out.

Saving the world, one semi-colon at a time.


You'll need to apply an attenuation to the lighting that takes into consideration the size of the bounding sphere.
So the lighting won't appear to be "clipped", it will gradually fade out.


I'm doing that but the result is the same, this is a piece of the PS (a very similar code is present on the tutorial that I've linked):



// Attenuation
float fAtten = 1.0 / dot(Attenuation, float3(1, lightDist, lightDist * lightDist));


// Diffuse
output += max(0, (lightColor * dot(float4(normal, 1.f), lightDir) * fAtten));

// Specular
output += max(0, (lightColor * specularIntensity * pow(dot(float4(normal, 1.f), halfAngle), specularPower) * fAtten));

float volumeAttenuation = saturate(1.0f - lightDist / lightRadius);

return output * volumeAttenuation;




// Attenuation
float fAtten = 1.0 / dot(Attenuation, float3(1, lightDist, lightDist * lightDist));


// Diffuse
output += max(0, (lightColor * dot(float4(normal, 1.f), lightDir) * fAtten));

// Specular
output += max(0, (lightColor * specularIntensity * pow(dot(float4(normal, 1.f), halfAngle), specularPower) * fAtten));

float volumeAttenuation = saturate(1.0f - lightDist / lightRadius);

return output * volumeAttenuation;



I can only guess that your lightRadius value is too large, though this shouldn't be the case. Have you tried scaling it to see the effect it has?

Saving the world, one semi-colon at a time.


I can only guess that your lightRadius value is too large, though this shouldn't be the case. Have you tried scaling it to see the effect it has?


I'll show you two example:
- This with a lightRadius of 0.5f
mgdexample1020110508004.th.png]

- This with a lightRadius of 50.f
mgdexample1020110508004.th.png


Maybe there's also a blending problem?

[quote name='MajorTom' timestamp='1304808032' post='4807831']
I can only guess that your lightRadius value is too large, though this shouldn't be the case. Have you tried scaling it to see the effect it has?


I'll show you two example:
- This with a lightRadius of 0.5f
mgdexample1020110508004.th.png]

- This with a lightRadius of 50.f
mgdexample1020110508004.th.png


Maybe there's also a blending problem?
[/quote]

It doesn't appear to be a blending problem. Try scaling the value in the shader i.e lightRadius*0.1f. Rather than scaling the geometry.
This might tell us if there's an issue with the attenuation code. It does seem a little odd though.

Are you applying the ambient lighting term for each light source? This would cause sharp edges also, as it's a constant value.
This should either be a single fullscreen pass or the colour used when clearing the render target. Just an idea.

Saving the world, one semi-colon at a time.

I've tried to use the same PS code presented in the tutorial that I've linked in the first post, this is the code:



float4 PS(VS_OUTPUT input) : SV_TARGET0
{
//obtain screen position
input.screenPosition.xy /= input.screenPosition.w;
//obtain textureCoordinates corresponding to the current pixel
//the screen coordinates are in [-1,1]*[1,-1]
//the texture coordinates need to be in [0,1]*[0,1]
float2 texCoord = 0.5f * (float2(input.screenPosition.x,-input.screenPosition.y) + 1);
//get normal data from the normalMap
float4 normalData = normalTexture.Sample(pointSampler, texCoord);
//tranform normal back into [-1,1] range
float3 normal = 2.0f * normalData.xyz - 1.0f;
//get specular power
float specularPower = normalData.a * 255;
//get specular intensity from the colorMap
float specularIntensity = colorTexture.Sample(linearSampler, texCoord).a;
//read depth
float depthVal = depthTexture.Sample(pointSampler, texCoord).r;
//compute screen-space position
float4 position;
position.xy = input.screenPosition.xy;
position.z = depthVal;
position.w = 1.0f;
//transform to world space
position = mul(position, InvertViewProjection);
position /= position.w;
//surface-to-light vector
float3 lightVector = lightPosition - position;
//compute attenuation based on distance - linear attenuation
float attenuation = saturate(1.0f - length(lightVector)/lightRadius);
//normalize light vector
lightVector = normalize(lightVector);
//compute diffuse light
float NdL = max(0,dot(normal,lightVector));
float3 diffuseLight = NdL * Color.rgb;
//reflection vector
float3 reflectionVector = normalize(reflect(-lightVector, normal));
//camera-to-surface vector
float3 directionToCamera = normalize(cameraPosition - position);
//compute specular light
float specularLight = specularIntensity * pow( saturate(dot(reflectionVector, directionToCamera)), specularPower);
//take into account attenuation and lightIntensity.
return attenuation * lightIntensity * float4(diffuseLight.rgb,specularLight);
}



and this is a result with a radius of 15.f:

mgdexample1020110508105.th.png

I think that this code have some problems, and the attenuation is not correct. Some suggestions?
Thanks.

Edit: If you watch the screenshot you can see that the columns at the bottom have the same light intensity applied.
Attenuation is supposed to have 3-components rather than 1 like you do it.

float fAtten = 1.0/dot(LightAttenuation, float4(1, fLightDist, fLightDist*fLightDist,0));

Thats how I'm doing it, and I get nice results. You have to try around a bit, but basically you set LightAtenuation in your application as a 4-component-vector, and set the 4th component to 0. But playing around with the other components will give you the effect that you want. Have a read here: MSDN

Attenuation is supposed to have 3-components rather than 1 like you do it.

float fAtten = 1.0/dot(LightAttenuation, float4(1, fLightDist, fLightDist*fLightDist,0));

Thats how I'm doing it, and I get nice results. You have to try around a bit, but basically you set LightAtenuation in your application as a 4-component-vector, and set the 4th component to 0. But playing around with the other components will give you the effect that you want. Have a read here: MSDN


Yes, it's true. Infact in my past code I've used the formula that you've posted.
With this the attenuation works fine (as you can see in the screenshot), but I've the same cutting edge effect. How can I solve that? I must tune the attenuation parameters?

mgdexample1020110508113.th.png
What is the relationship between [font=CourierNew, monospace][size=2]lightDist[/font] and the size of the sphere exactly?

This topic is closed to new replies.

Advertisement