EEVEE-Next: Improve shadow map filter
This make the filter have a constant width in shadow space making sure to always filter the correct amount of pixels. This uses the receiver slope to put the samples on a cone with its apex at the shading position instead of setting up the disk in shading tangent space. We limit the slope bias to 45 degrees and offset the cone in normal direction if the angle between light and receiver is greater than 45 degrees. This avoid any self shadowing artifacts cause by this technique. Pull Request: https://projects.blender.org/blender/blender/pulls/122266
This commit is contained in:
committed by
Clément Foucault
parent
f93360b3bb
commit
03bcd70cd1
@@ -316,18 +316,22 @@ SHADOW_MAP_TRACE_FN(ShadowRayPunctual)
|
||||
* stochastic percentage closer filtering of shadow-maps. */
|
||||
vec3 shadow_pcf_offset(vec3 L, vec3 Ng, vec2 random)
|
||||
{
|
||||
/* Angle between Light and normal. */
|
||||
float cos_theta = abs(dot(L, Ng));
|
||||
float sin_theta = sin_from_cos(cos_theta);
|
||||
/* Slope of the receiver plane with respect to light direction. Equal to `tan(theta)`.
|
||||
* Stop at 45° angle to avoid large bias and peter panning artifacts. */
|
||||
float cone_height = saturate(sin_theta * safe_rcp(cos_theta));
|
||||
/* We choose a random disk distribution because it is rotationally invariant.
|
||||
* This sames us the trouble of getting the correct orientation for punctual. */
|
||||
vec2 disk_sample = sample_disk(random);
|
||||
/* Compute the offset as a disk around the normal. */
|
||||
mat3x3 tangent_frame = from_up_axis(Ng);
|
||||
vec3 pcf_offset = tangent_frame[0] * disk_sample.x + tangent_frame[1] * disk_sample.y;
|
||||
|
||||
if (dot(pcf_offset, L) < 0.0) {
|
||||
/* Reflect the offset to avoid overshadowing caused by moving the sampling point below another
|
||||
* polygon behind the shading point. */
|
||||
pcf_offset = reflect(pcf_offset, L);
|
||||
}
|
||||
* This saves us the trouble of getting the correct orientation for punctual. */
|
||||
float distance_to_center = sqrt(random.x);
|
||||
vec2 disk_sample = sample_circle(random.y) * distance_to_center;
|
||||
/* Set the samples on a cone up to 45 degree. */
|
||||
vec3 cone_sample = vec3(disk_sample, distance_to_center * cone_height);
|
||||
/* Setup the cone around the light vector. */
|
||||
vec3 pcf_offset = from_up_axis(L) * cone_sample;
|
||||
/* Offset the cone in normal direction to avoid self shadowing when angle is greater than 45°. */
|
||||
pcf_offset += Ng * saturate(sin_theta - cos_theta);
|
||||
return pcf_offset;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user