Skip to main content
Added graphic and pseudo-code explaining the inner workings of sampler2DShadow vs sampler2D
Source Link
Stephane Hockenhull
  • 12.1k
  • 1
  • 26
  • 44

try using a multiplicative "bias" instead of additive:

shadowCoordinate.z *= 0.98; 

If you're doing the sampling yourself rather than using the shadow comparator interpolating the shadow map helps reduce acne a lot.

There shouldn't be any shadow visible behind the object as the light should not affect it with the light being completely occluded by the object itself.

Global ambient light should not be affected by shadows, shadows should only cuts off the light that is casting the shadow not the other lights.

vec3 output_color = ambient * material_diffuse; foreach(light){ float shadow_masking = light.CalculateShadow(); output_color += light.Calculate(material_diffuse, material_specular) * shadow_masking; } 

Here's 3 colored point lights using cubemap shadow casting and 1 directional. Shadow maps are rendered front-face (the usual back-face culling). Single-pass forward-shading. And a multiplicative "bias" of 1.02 applied to the shadow depth. Shadow map depth is interpolated. The columns grooves are actually modeled (not normal maps) to stress test self-shadowing and shadow acne issues. The 3 small spheres are the point light sources. Rendered on an nVidia GTX 560M. The minimum requirement is GLSL 1.1 (OpenGL 2.0). multiple light sources 3 points, 1 directional

Edit: Adding pseudo-code of the internals of sample2DShadow vs sampler2D

sample2DShadow:

float A = Nearest(tex, floor(coord.xy + vec2(0, 0))).r < coord.z ? 1.0 : 0.0; float B = Nearest(tex, floor(coord.xy + vec2(1, 0))).r < coord.z ? 1.0 : 0.0; float C = Nearest(tex, floor(coord.xy + vec2(0, 1))).r < coord.z ? 1.0 : 0.0; float D = Nearest(tex, floor(coord.xy + vec2(1, 1))).r < coord.z ? 1.0 : 0.0; return Lerp( Lerp(A, B, fract(coord.x)), Lerp(C, D, fract(coord.x)), fract(coord.y)); 

sampler2D on depth texture:

vec4 A = Nearest(tex, floor(coord.xy + vec2(0, 0))).rrrr; vec4 B = Nearest(tex, floor(coord.xy + vec2(1, 0))).rrrr; vec4 C = Nearest(tex, floor(coord.xy + vec2(0, 1))).rrrr; vec4 D = Nearest(tex, floor(coord.xy + vec2(1, 1))).rrrr; return Lerp( Lerp(A, B, fract(coord.x)), Lerp(C, D, fract(coord.x)), fract(coord.y)); 

Both types of samplers do 1 bilinear interpolation, but the sampler2DShadow does it on the boolean result.

enter image description here

try using a multiplicative "bias" instead of additive:

shadowCoordinate.z *= 0.98; 

If you're doing the sampling yourself rather than using the shadow comparator interpolating the shadow map helps reduce acne a lot.

There shouldn't be any shadow visible behind the object as the light should not affect it with the light being completely occluded by the object itself.

Global ambient light should not be affected by shadows, shadows should only cuts off the light that is casting the shadow not the other lights.

vec3 output_color = ambient * material_diffuse; foreach(light){ float shadow_masking = light.CalculateShadow(); output_color += light.Calculate(material_diffuse, material_specular) * shadow_masking; } 

Here's 3 colored point lights using cubemap shadow casting and 1 directional. Shadow maps are rendered front-face (the usual back-face culling). Single-pass forward-shading. And a multiplicative "bias" of 1.02 applied to the shadow depth. Shadow map depth is interpolated. The columns grooves are actually modeled (not normal maps) to stress test self-shadowing and shadow acne issues. The 3 small spheres are the point light sources. Rendered on an nVidia GTX 560M. The minimum requirement is GLSL 1.1 (OpenGL 2.0). multiple light sources 3 points, 1 directional

try using a multiplicative "bias" instead of additive:

shadowCoordinate.z *= 0.98; 

If you're doing the sampling yourself rather than using the shadow comparator interpolating the shadow map helps reduce acne a lot.

There shouldn't be any shadow visible behind the object as the light should not affect it with the light being completely occluded by the object itself.

Global ambient light should not be affected by shadows, shadows should only cuts off the light that is casting the shadow not the other lights.

vec3 output_color = ambient * material_diffuse; foreach(light){ float shadow_masking = light.CalculateShadow(); output_color += light.Calculate(material_diffuse, material_specular) * shadow_masking; } 

Here's 3 colored point lights using cubemap shadow casting and 1 directional. Shadow maps are rendered front-face (the usual back-face culling). Single-pass forward-shading. And a multiplicative "bias" of 1.02 applied to the shadow depth. Shadow map depth is interpolated. The columns grooves are actually modeled (not normal maps) to stress test self-shadowing and shadow acne issues. The 3 small spheres are the point light sources. Rendered on an nVidia GTX 560M. The minimum requirement is GLSL 1.1 (OpenGL 2.0). multiple light sources 3 points, 1 directional

Edit: Adding pseudo-code of the internals of sample2DShadow vs sampler2D

sample2DShadow:

float A = Nearest(tex, floor(coord.xy + vec2(0, 0))).r < coord.z ? 1.0 : 0.0; float B = Nearest(tex, floor(coord.xy + vec2(1, 0))).r < coord.z ? 1.0 : 0.0; float C = Nearest(tex, floor(coord.xy + vec2(0, 1))).r < coord.z ? 1.0 : 0.0; float D = Nearest(tex, floor(coord.xy + vec2(1, 1))).r < coord.z ? 1.0 : 0.0; return Lerp( Lerp(A, B, fract(coord.x)), Lerp(C, D, fract(coord.x)), fract(coord.y)); 

sampler2D on depth texture:

vec4 A = Nearest(tex, floor(coord.xy + vec2(0, 0))).rrrr; vec4 B = Nearest(tex, floor(coord.xy + vec2(1, 0))).rrrr; vec4 C = Nearest(tex, floor(coord.xy + vec2(0, 1))).rrrr; vec4 D = Nearest(tex, floor(coord.xy + vec2(1, 1))).rrrr; return Lerp( Lerp(A, B, fract(coord.x)), Lerp(C, D, fract(coord.x)), fract(coord.y)); 

Both types of samplers do 1 bilinear interpolation, but the sampler2DShadow does it on the boolean result.

enter image description here

Source Link
Stephane Hockenhull
  • 12.1k
  • 1
  • 26
  • 44

try using a multiplicative "bias" instead of additive:

shadowCoordinate.z *= 0.98; 

If you're doing the sampling yourself rather than using the shadow comparator interpolating the shadow map helps reduce acne a lot.

There shouldn't be any shadow visible behind the object as the light should not affect it with the light being completely occluded by the object itself.

Global ambient light should not be affected by shadows, shadows should only cuts off the light that is casting the shadow not the other lights.

vec3 output_color = ambient * material_diffuse; foreach(light){ float shadow_masking = light.CalculateShadow(); output_color += light.Calculate(material_diffuse, material_specular) * shadow_masking; } 

Here's 3 colored point lights using cubemap shadow casting and 1 directional. Shadow maps are rendered front-face (the usual back-face culling). Single-pass forward-shading. And a multiplicative "bias" of 1.02 applied to the shadow depth. Shadow map depth is interpolated. The columns grooves are actually modeled (not normal maps) to stress test self-shadowing and shadow acne issues. The 3 small spheres are the point light sources. Rendered on an nVidia GTX 560M. The minimum requirement is GLSL 1.1 (OpenGL 2.0). multiple light sources 3 points, 1 directional