Hi all,
My renderer currently has PBR shading and shadow maps for one directional light. Now I want to add shadows for point lights as well. The shadows I have so far are based on the examples provided by kosmonautgames in this thread and it’s working great.
For the point lights I have generated cube maps for each light, but I’m just struggling with how to now apply those cube maps. I know it’s similar to what I have for the directional light, I think I just need a bit more code to calculate which face of the cube map to use.
Here’s the relevant parts of my shader: the function that calculates the shadows, and the lighting for the direcitonal and point lights. You can see how I have the shadows working for the directional light already, just not sure how to modify that to use a cube map for the point lights.
//----------------------------------------------------------------------------------
// Calculates the shadow term using PCF
//----------------------------------------------------------------------------------
float CalcShadowTermPCF(float light_space_depth, float ndotl, float2 shadow_coord)
{
float shadow_term = 0;
float variableBias = clamp(0.001 * tan(acos(ndotl)), 0, _DepthBias);
//safe to assume it's a square
float size = 1 / _ShadowMapSize;
float samples[4];
samples[0] = (light_space_depth - variableBias < _ShadowMap.Sample(ShadowMapSampler, shadow_coord).r);
samples[1] = (light_space_depth - variableBias < _ShadowMap.Sample(ShadowMapSampler, shadow_coord + float2(size, 0)).r);
samples[2] = (light_space_depth - variableBias < _ShadowMap.Sample(ShadowMapSampler, shadow_coord + float2(0, size)).r);
samples[3] = (light_space_depth - variableBias < _ShadowMap.Sample(ShadowMapSampler, shadow_coord + float2(size, size)).r);
shadow_term = (samples[0] + samples[1] + samples[2] + samples[3]) / 4.0;
return shadow_term;
}
//----------------------------------------------------------------------------------
// Lights
//----------------------------------------------------------------------------------
float3 CalculatePointLights(float3 worldPosition, float3 N, float3 albedo, float metallic, float roughness)
{
float3 V = normalize(_CameraPos - worldPosition);
//Calculate surface reflection at zero incidence, default to 0.04 but adjust for metallic surfaces.
float3 F0 = float3(0.04, 0.04, 0.04);
F0 = lerp(F0, albedo, metallic);
//Reflection equation
float3 Lo = float3(0.0, 0.0, 0.0);
for(int i = 0; i < MaxPointLights; ++i)
{
// calculate per-light radiance
float3 L = normalize(_PointLightPos[i] - worldPosition);
float3 H = normalize(V + L);
float distance = length(_PointLightPos[i] - worldPosition);
float attenuation = _PointLightRange[i] / (distance * distance);
float3 radiance = _PointLightColors[i] * attenuation * _PointLightIntensity[i];
// cook-torrance brdf
float NDF = DistributionGGX(N, H, roughness);
float G = GeometrySmith(N, V, L, roughness);
float3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
float3 kS = F;
float3 kD = float3(1.0, 1.0, 1.0) - kS;
kD *= 1.0 - metallic;
float3 numerator = NDF * G * F;
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);
float3 specular = numerator / max(denominator, 0.001);
// add to outgoing radiance Lo
float NdotL = max(dot(N, L), 0.0);
//Shadows
float shadowContribution = 1.0;
//TO DO: Read shadow maps here
//_ShadowCubes: One point light's shadow map stored as a cube map
//_PointLightSpaceMatrix: Array of 6 view projection matrices for the point light
Lo += (kD * albedo / PI + specular) * radiance * NdotL * shadowContribution;
}
return Lo;
}
float3 CalculateDirectionalLights(float3 worldPosition, float3 N, float3 albedo, float metallic, float roughness)
{
float3 V = normalize(_CameraPos - worldPosition);
//Calculate surface reflection at zero incidence, default to 0.04 but adjust for metallic surfaces.
float3 F0 = float3(0.04, 0.04, 0.04);
F0 = lerp(F0, albedo, metallic);
//Reflection equation
float3 Lo = float3(0.0, 0.0, 0.0);
for(int i = 0; i < MaxDirectionalLights; ++i)
{
// calculate per-light radiance
float3 L = -_DirectionalLights[i];
float3 H = normalize(V + L);
float3 radiance = _DirectionalColors[i] * _DirectionalIntensity[i];
// cook-torrance brdf
float NDF = DistributionGGX(N, H, roughness);
float G = GeometrySmith(N, V, L, roughness);
float3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
float3 kS = F;
float3 kD = float3(1.0, 1.0, 1.0) - kS;
kD *= 1.0 - metallic;
float3 numerator = NDF * G * F;
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);
float3 specular = numerator / max(denominator, 0.001);
float NdotL = max(dot(N, L), 0.0);
//Shadows
float shadowContribution = 1.0;
if(i == _DirectionalShadowIndex)
{
float4 lightingPosition = mul(float4(worldPosition, 1), _LightSpaceMatrix);
float2 shadowTexCoord = mad(0.5, lightingPosition.xy / lightingPosition.w, float2(0.5, 0.5));
shadowTexCoord.y = 1.0f - shadowTexCoord.y;
float ourDepth = (lightingPosition.z / lightingPosition.w);
shadowContribution = CalcShadowTermPCF(ourDepth, NdotL, shadowTexCoord);
}
// add to outgoing radiance Lo
Lo += (kD * albedo / PI + specular) * radiance * NdotL * shadowContribution;
}
return Lo;
}
Can anyone provide any guidance?
Thanks