Advertisement

Less ifs in shadow HLSL / spotlight shader

Started by October 12, 2024 06:33 PM
2 comments, last by cozzie 3 days, 1 hour ago

Hi all,

Now that I've got my shadowmapping implementation working, I noticed I'm doing quite some ‘ifs’/ branching in my shader. In general I know it's best to minimize those and where possible replace with multiplication with 1 generic formula instead.

Any idea if/ how I could apply that better here?

// spot lights
[unroll]
for(uint sl=0;sl<gPerObject.NrSpotLightsAff;++sl)
{
uint lightId = gPerObject.SpotLightsAff[sl/4][sl%4];
float3 projColor = float3(1.0f, 1.0f, 1.0f);
if(gPerScene.LightSources[lightId].ProjectedTex)
{
uint texIndex = gPerScene.LightSources[lightId].LengthOrProjTexIndex;

float2 projUV = pin.SpotLightSpacePos[sl].xy / pin.SpotLightSpacePos[sl].w;
float2 projUVnorm = projUV * float2(0.5, -0.5) + 0.5;

projColor = gLightMap.Sample(gTexSampler, float3(projUVnorm, texIndex)).rgb;
}
float shadowFactor = 1.0f;
if(gPerScene.LightSources[lightId].CastShadows)
{
float4 lightSpacePos = pin.SpotLightSpacePos[sl];
lightSpacePos.xyz /= lightSpacePos.w;

if(LightInRange(lightSpacePos))
{
shadowFactor = GetShadowFactor(lightSpacePos, gPerScene.LightSources[lightId].SpotShadowMapIndex);
}
}
CalcSpotLight(gPerScene.LightSources[lightId], pin.PosW, toEye, lightSetup, projColor, shadowFactor);
}
And:

void CalcSpotLight(LightSource pSpotLight, float3 pPos, float3 pToEye, inout LightSetup pLightSetup, float3 pProjColor, float pShadowFactor)
{
if(!any(pSpotLight.ColorIntensity.rgb)) return;
if(pShadowFactor == 0.0f) return;

Any input is appreciated.

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

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

cozzie said:
I noticed I'm doing quite some ‘ifs’/ branching in my shader. In general I know it's best to minimize those and where possible replace with multiplication with 1 generic formula instead.

It's even better to ensure that all threads of a group take the same branch where possible.
As far as i interpret your code, that's the case everywhere. So your branches cause no cost (aside the test itself, which you need anyway).
My assumption is: All threads of any group iterate the same list of lights. They all process the same light at any time, so they will take the same branches and divergence is zero.

This remains important if you would introduce lights binned to screen tiles in the future, e.g. to increase the number of lights you can handle. You would make sure that the shading thread groups align to the tiles, so you still have the same advantage allthough the list is now different across tiles.
That's easy with compute shaders, since it gives you precise control over thread groups.
For pixel shaders you would need to reserach how GPUs orginize pixel shader thread groups spatially, but likely any power of two dimensions for the tiles would work.

Advertisement

Thanks @joej , I'll move forward for now. Tile based rendering is somewhere low(er) on the list.

First need to add proper directional light (cascaded) shadowmaps.

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

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

Advertisement