Author Topic: Screen space shadows  (Read 2015 times)

0 Members and 1 Guest are viewing this topic.


  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2591
Screen space shadows
« on: July 07, 2020, 10:55:54 AM »
After working on Spartan game engine for so long, it became increasingly obvious that there are many interesting things that I could be writing about. However, I kept postponing it as I was growing fond of Hugo and didn’t want to invest any content (or money) on WordPress anymore. The good thing is that I’ve finally found the courage to transition to this slick and fast site you’re browsing now!

I want to start things off with a simple and short blog post, yet have some immediate results we can enjoy. You know, something like the kind of instant gratification you get by watching a Bob Ross episode. An approach which I believe to be one of the most efficient forms of conveying information. So, let’s explore something that with a little bit of effort, might give us just that. Time for some screen space shadows


Loss of small-scale detail when doing shadow mapping is a typical problem, especially with lights that aim to cover a large portion of the scene (like directional lights). As we’ve seen, screen space shadows can help a lot but before we explore them in further detail, let’s see how most of the games we enjoy handle small-scale shadow quality:

- The player is allowed to keep increasing the shadow resolution. It’s a costly approach but it works and it happens to be the most common.
- The player sees lights with very high shadow resolution, during key moments like character close-ups. This approach doesn’t suffer from typical screen space issues but it does involve the hard work of manually tweaking lights, per scene.
- The player gets the extra treatment that is screen space shadows. In some cases, the shadows are even aided by information from other render passes, which helps alleviate some screen space issues even further.

Full article:

Screen space shadow demo

Code: [Select]
// Settings
static const uint  g_sss_steps            = 8;     // Quality/performance
static const float g_sss_ray_max_distance = 0.05f; // Max shadow length
static const float g_sss_tolerance        = 0.01f; // Error in favor of reducing gaps
static const float g_sss_step_length      = g_sss_ray_max_distance / (float)g_sss_steps;

float ScreenSpaceShadows(Surface surface, Light light)
    // Compute ray position and direction (in view-space)
    float3 ray_pos = mul(float4(surface.position, 1.0f), g_view).xyz;
    float3 ray_dir = mul(float4(-light.direction, 0.0f), g_view).xyz;

    // Compute ray step
    float3 ray_step = ray_dir * g_sss_step_length;

    // Ray march towards the light
    float occlusion = 0.0;
    float2 ray_uv   = 0.0f;
    for (uint i = 0; i < g_sss_steps; i++)
        // Step the ray
        ray_pos += ray_step;
        // Compute the difference between the ray's and the camera's depth
        ray_uv            = project_uv(ray_pos, g_projection);
        float depth_z     = get_linear_depth(ray_uv);
        float depth_delta = ray_pos.z - depth_z;
        // If the ray is behind what the camera "sees" (positive depth_delta)
        if (abs(g_sss_tolerance - depth_delta) < g_sss_tolerance)
            // Consider the pixel to be shadowed/occluded
            occlusion = 1.0f;

    // Fade out as we approach the edges of the screen
    occlusion *= screen_fade(ray_uv);
    return 1.0f - occlusion;