Jump to content
  • Advertisement

DX11 Is there a quick way to fix peter panning (shadows detaching from objects)

Recommended Posts

My shadows (drawn using a depth buffer which I later sample from in the shadow texture), seem to be detaching slightly from their objects.

 

I looked this up and I think it's "peter panning," and they were saying you have to change the depth offset, but not sure how to do that.

https://msdn.microsoft.com/en-us/library/windows/desktop/ee416324(v=vs.85).aspx

 

Is there a fast way I can tweak the code to fix this? Should I change the "bias" perhaps, or something else? Thanks,

Here is the code for the shadows, for reference:

// ENTRY POINT
float4 main(PixelInputType input) : SV_TARGET
{
    float2 projectTexCoord;
    float depthValue;
    float lightDepthValue;
    //float4 lightColor = float4(0,0,0,0);
    float4 lightColor = float4(0.05,0.05,0.05,1);

    // Set the bias value for fixing the floating point precision issues.
    float bias = 0.001f;

    //////////////// SHADOWING LOOP ////////////////
    for(int i = 0; i < NUM_LIGHTS; ++i)
    {
    // Calculate the projected texture coordinates.
    projectTexCoord.x =  input.vertex_ProjLightSpace[i].x / input.vertex_ProjLightSpace[i].w / 2.0f + 0.5f;
    projectTexCoord.y = -input.vertex_ProjLightSpace[i].y / input.vertex_ProjLightSpace[i].w / 2.0f + 0.5f;

    if((saturate(projectTexCoord.x) == projectTexCoord.x) && (saturate(projectTexCoord.y) == projectTexCoord.y))
    {
        // Sample the shadow map depth value from the depth texture using the sampler at the projected texture coordinate location.
        depthValue = depthTextures[i].Sample(SampleTypeClamp, projectTexCoord).r;

        // Calculate the depth of the light.
        lightDepthValue = input.vertex_ProjLightSpace[i].z / input.vertex_ProjLightSpace[i].w;

        // Subtract the bias from the lightDepthValue.
        lightDepthValue = lightDepthValue - bias;

        // Compare the depth of the shadow map value and the depth of the light to determine whether to shadow or to light this pixel.
        // If the light is in front of the object then light the pixel, if not then shadow this pixel since an object (occluder) is casting a shadow on it.
            if(lightDepthValue < depthValue)
            {
                // Calculate the amount of light on this pixel.
                float lightIntensity = saturate(dot(input.normal, normalize(input.lightPos_LS[i])));

                if(lightIntensity > 0.0f)
                {
                    float spotlightIntensity = CalculateSpotLightIntensity(input.lightPos_LS[i], cb_lights[i].lightDirection, input.normal);
                    //lightColor += (float4(1.0f, 1.0f, 1.0f, 1.0f) * lightIntensity) * .3f; // spotlight
                    lightColor += float4(1.0f, 1.0f, 1.0f, 1.0f) /** lightIntensity*/ * spotlightIntensity * .3f; // spotlight
                }
            }
        }
    }

    return saturate(lightColor);
}

https://github.com/mister51213/DirectX11Engine/blob/master/DirectX11Engine/MultiShadows_ps.hlsl

 

peterpanning.PNG

Share this post


Link to post
Share on other sites
Advertisement

The purpose of the depth offset (called bias in your code) is to prevent objects causing themselves to be in shadow due (which you can see if you set it to zero)

So try reducing it slightly maybe half it to .0005f

That should move the shadows slightly closer to the object, but if you reduce it too far it may cause self shadows in which case you would have to increase it slightly maybe to .0008f

Play around with its value to make it look right

 

Edited by CortexDragon

Share this post


Link to post
Share on other sites

You can also try SlopeScaledDepthBias in the Rasterizer State settings to have better shadows when the light not faces geometry straight but sloped.

You can also draw your objects in the shadow map with reversed culling order, so culling front faces instead of backfaces. Or disabling culling could also help.

Share this post


Link to post
Share on other sites

The short answer is no. The longer answer is also no. Nothing is ever simple with shadows in real time rendering.

 

The problem is that a shadow-map texel will cover a variable amount of screen pixels. The well seen result without any counter measure is aliasing as the surface on screen goes up and down the unique shadow map texel. The problem get worse with shadow map bluring like multi tap PCF because you end fetching further, increasing odds of false positive and negatives.

 

Depth bias of any sort, as at shadow map render or as shadow test read are a useful tool but are never perfect. The idea is to push the whole scissor like stairs depth of the shadow map texels under the screen surface. By definition, they generate your peter panning effect. You can have lighting artist spending their days tweaking the biasing for every light and still not have a perfect result. The slope based bias is making your bias bigger where the acne is the most likely ( perpendicular surface that will extend over way more on screen projection ), and by so, will add even more floating :)

 

If you look at recent attempt to solve that, there is a "crazy" technique doing real raytrace up close that then blend to shadow map. The demo came from nVidia and have been implemented at least once (afaik) in Battlefield 1 for their Sun.

Share this post


Link to post
Share on other sites
8 hours ago, turanszkij said:

You can also try SlopeScaledDepthBias in the Rasterizer State settings to have better shadows when the light not faces geometry straight but sloped.

You can also draw your objects in the shadow map with reversed culling order, so culling front faces instead of backfaces. Or disabling culling could also help.

Thanks great tips Turanzkij. Quick questions

1) I see SlopeScaledDepthBias is currently set 0 in my engine - what value do you suggest I set?

2) Will changing it cause problems w the rendering of the other objects in the scene?

3) Can I change the SlopeScaledDepthBias dynamically (set it to one value before I draw the shadows and back to 0 after I draw them)?

3) For reversed culling, I should turn off culling right before I draw the shadows to the depth map, and then turn culling on again afterwards, is that correct?

Edited by mister345

Share this post


Link to post
Share on other sites
9 hours ago, mister345 said:

Thanks great tips Turanzkij. Quick questions

1) I see SlopeScaledDepthBias is currently set 0 in my engine - what value do you suggest I set?

2) Will changing it cause problems w the rendering of the other objects in the scene?

3) Can I change the SlopeScaledDepthBias dynamically (set it to one value before I draw the shadows and back to 0 after I draw them)?

3) For reversed culling, I should turn off culling right before I draw the shadows to the depth map, and then turn culling on again afterwards, is that correct?

  1. Sorry I am not sure. Best to leave it unless you find a value that actually helps you. You can read about how it affects the bias calculation: MSDN
  2. Only change it for the rasterizer state which you use for shadow rendering. You should use separate rasterizer states for shadow rendering and normal object rendering.
  3. You can do that if you follow my suggestion to use separate rasterizer states for shadow and normal object rendering.
  4. Only turn on reversed culling for the shadow map rendering rasterizer state. Though this can eliminate peter-panning, it can introduce other problems.

Good luck!

 

Share this post


Link to post
Share on other sites
38 minutes ago, turanszkij said:
  1. Sorry I am not sure. Best to leave it unless you find a value that actually helps you. You can read about how it affects the bias calculation: MSDN
  2. Only change it for the rasterizer state which you use for shadow rendering. You should use separate rasterizer states for shadow rendering and normal object rendering.
  3. You can do that if you follow my suggestion to use separate rasterizer states for shadow and normal object rendering.
  4. Only turn on reversed culling for the shadow map rendering rasterizer state. Though this can eliminate peter-panning, it can introduce other problems.

Good luck!

 

When I switch to front face culling, it introduced new gaps in teh shadows, so I had to completely turn off culling - seemed to improve, but with a 10 frame drop!

For bias, I found these values online, they seem to be based on Frank Luna -

RasterizerState Depth
{
    DepthBias = 10000;
    DepthBiasClamp = 0.0f;
    SlopeScaledDepthBias = 1.0f;
};

I set the bias to the above numbers (they used to all be 0 by default), honestly cant tell if it makes any difference.

Share this post


Link to post
Share on other sites

@mister345 An other thing to consider is the precision of your shadow maps. 32bit floating point shadow maps will get you much better precision than a 16bit integer one. And it also affects the bias calculations, so you must use different bias values for them.

In my engine I am currently using depthbiasclamp = 0, depthbias = 0, slopescaleddepthbias = -2.0f values for the shadow rasterizers. Additionally I can set a bias per light which will be calculated in the pixel shader before comparing the shadow map and reference depths by simply adding the bias value to the reference depth (spotlight, directional light). For point lights I calculate the bias like this: 

// dist is distance between light and pixel world pos
float referenceDist = 1 - dist / light.range * (1 - light.shadowBias);

Note that my point lights are storing distances in the shadow map, not depth like spotlight and directional light.

An in my engine, all shadow maps are 16 bits integer (DXGI_FORMAT_D16_UNORM).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
  • Advertisement
  • Popular Tags

  • Popular Now

  • Advertisement
  • Similar Content

    • By LuigiLuigi
      I've been working on my own Metroidvania via GameMaker Studio for the past few years. You play as a bat named Ralph as he goes on an adventure to obtain 7 Crystal Medallions hidden in dungeons with the help of a cult known as the Crimson Fog. Along the way, there will be quests unlocked in Cedrus Village as you progress through the game. I've managed to complete a demo of the game up to the first dungeon and boss fight.
      I have only a PC build available, and the only gamepads I managed to install were Logitech Precision and Xbox PC gamepads. I had some trouble on gamepad detection though, so they may have connection issues. The desktop controls are similar to Terarria's control scheme if it's too much trouble. I don't have any music at this point, I'll need to get someone else to compose it later on. The music I make isn't bad, but it doesn't fit the aesthetic that well.
      I'm really hoping I can get feedback regarding the general content.
      Crimson Fog.0.2.zip
    • By mmmax3d
      Hi everyone,
      I would need some assistance from anyone who has a similar experience
      or a nice idea!
      I have created a skybox (as cube) and now I need to add a floor/ground.
      The skybox is created from cubemap and initially it was infinite.
      Now it is finite with a specific size. The floor is a quad in the middle
      of the skybox, like a horizon.
      I have two problems:
      When moving the skybox upwards or downwards, I need to
      sample from points even above the horizon while sampling
      from the botton at the same time.  I am trying to create a seamless blending of the texture
      at the points of the horizon, when the quad is connected
      to the skybox. However, I get skew effects. Does anybody has done sth similar?
      Is there any good practice?
      Thanks everyone!
    • By 4d3d
      Hi there,
      I've been away from 3d Art whilst on Maternity leave and just started to get an hour a day (if i'm lucky) to model while my baby sleeps. This is also my reason for picking something small. Really i'm after some feedback, good or bad, on any improvements, tips on rendering etc. 

      Any feedback would be massively appreciated as my time is so precious at the moment that i don't often have time to watch tutorials and research techniques so anything to point me in the right direction would be great.

      I've baked down from High-poly and exposed some custom color changing, decals, and number plate naming from substance designer and imported to marmoset.



    • By lucky6969b
      Dear folks,
      How do I calculate the axis of rotation between 2 vectors, one of them is the source directional vector, and the second is the destination directional vector.
      Thanks a lot
      Jack
    • By Alexander Winter
      Jumpaï is a game about creating platformer levels and playing them online with everyone. Will you become the most popular level maker or will you be a speedrunner holding world records on everyone's levels? More into casual play? No problem! You can happily play through the giant level database or chill at people's hub. Meet new people, make new friends, learn to master the game by asking pros or ask for people's favorite tricks on level making. Download here: https://jumpai.itch.io/jumpai Discord: https://discord.gg/dwRTNCG   Trailer:      (The following screenshots are older but still a bit representative)  





      Unlike other games of its genre, Jumpaï is about playing levels with everyone in real time. You have the fun to see how other people are playing and get to realize you are not the only one failing that jump!

      The game is currently into development and still have lots to do. I am looking for people willing to help how they can. Developer? Graphist? Play tester? Sound designer? Game designer? I'm welcoming any talent. The project is so big I have a lot of work to do in all areas. Server backend, UI/UX, Game networking, Gameplay and even the website some day. As you can see from the default buttons, the game has been made with LibGDX. This project is a perfect opportunity for you to get better in various fields as well as showing off your skills.

      If you plan to take an important role into the development of the game, we will discuss how you will get paid once the game generates money. Note that I'm not working on the game full-time. I'm studying full-time and working on it is a hobby. The project has started in november 2016 and experiences heavy progress.

      So, are you interested? If so join me on my discord https://discord.gg/dwRTNCG and I'll answer all your questions.

      Additionnal screenshots:
       



       
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!