I’ve got point-light shadows implemented.
I get the projection matrix like this:
struct PointLight
{
glm::vec4 colorIntensity;
glm::vec3 position;
float radius;
};
glm::mat4 getPointShadowProjection(float radius)
{
return glm::perspectiveZO(glm::radians(90.0f), 1.0f, 0.01f, radius);
}
far plane
is the same as the radius.
and then in shadow fragment shader I also save linearized depth value
gl_FragDepth = length(worldPosition - lightPos) / farPlane;
where far plane
is just the light radius.
For distance attenuation with squared inverse radius, it works fine (GLSL):
float getSquareFalloffAttenuation(float distanceSquare, float falloff)
{
float factor = distanceSquare * falloff;
float smoothFactor = saturate(1.0 - factor * factor);
return smoothFactor * smoothFactor;
}
float getDistanceAttenuation(vec3 posToLight, float falloff)
{
vec2 lightFarAttenuationParams = vec2(5.0f, 0.0005f);
float distanceSquare = dot(posToLight, posToLight);
float attenuation = getSquareFalloffAttenuation(distanceSquare, falloff);
highp vec3 v = worldPosition - cameraPosition;
attenuation *= saturate(lightFarAttenuationParams.x - dot(v, v) * lightFarAttenuationParams.y);
return attenuation / max(distanceSquare, 1e-4);
}
vec3 CalculateLight(uint lightIndex, PointLight light)
{
vec3 posToLight = ...;
float sqFalloff = light.radius * light.radius;
float squaredFallOffInv = sqFalloff > 0.0f ? (1 / sqFalloff) : 0;
float attenuation = getDistanceAttenuation(posToLight, squaredFallOffInv);
float shadow = PointShadow(lightIndex, worldPosition, light.position, light.radius);
//the rest is not important
...
}
uniform samplerCubeArrayShadow u_pointShadowMap;
float PointShadow(uint index, vec3 worldPosition, vec3 lightPos, float radius)
{
vec3 fragToLight = worldPosition - lightPos;
float currentDepth = (length(fragToLight) - 0.05f) / radius;
return texture(u_pointShadowMap, vec4(fragToLight, index), currentDepth);
}
but I want to use the solid angle instead of distance attenuation:
float CalculateSolidAngle(const float r, const float d)
{
const float r2 = r * r;
const float d2 = d * d;
const float h = 1.0f - sqrt(1.0f - min(r2 / d2, 1.0f));
return PI_2 * h;
}
vec3 CalculateLight(uint lightIndex, PointLight light)
{
vec3 posToLight = ...;
float attenuation = CalculateSolidAngle(light.radius, length(posToLight));
float shadow = PointShadow(lightIndex, worldPosition, light.position, light.radius);
//the rest is not important
...
}
then I cannot just use the radius
as a far plane, because it’s too small.
How should I then calculate the shadow far plane?