• Advertisement

3D Shadow Shimmering When Moving Objects

Recommended Posts

Dears,

I am having a shadow shimmering in my scene. I am using shadow mapping technique. I know that there is a lot of posts over the internet dealing with this subject but My issue is slightly different.

I know that the problem comes from sub-texel issue when moving the camera BUT My scene is using a different technique as the camera and the light sources are stable and the objects inside the scene is moving Relative To Eye concept (RTE). The issue is when implementing cascaded shadow mapping and variance shadow mapping as stated in Directx examples, Every thing goes well except that the shadows are shimmering (Flickering). The shimmering is coming from that the objects are moving not the camera. So when I try to solve the problem with adjusting the sub-texel problem with the camera movement it didn't solve the problem as the camera is stable but the objects are not. 

Any help will be appreciated.

Thanks in advance.

Share this post


Link to post
Share on other sites
Advertisement

This is expected. The typical "stabilization"  techniques for cascade shadow maps only fix flickering for the case of completely static geometry. If the geometry moves or otherwise animates, you'll get flickering due to changes in how the geometry rasterizes into the depth map. The only way to avoid this this is to apply filtering when sampling the shadow map (or potentially pre-filter, if you're using a technique like VSM that supports pre-filtering).

Share this post


Link to post
Share on other sites
8 minutes ago, Aressera said:

Maybe you could quantize the positions of objects to texels when rendering the shadow map (but only the shadow map)?

I think you could only do that for ortho shadow maps, not for perspective or omnidirectional. And it would introduce wrong self shadowing anyway if you only do it for the shadow maps.

Share this post


Link to post
Share on other sites

What works pretty well is temporal filtering, this causes temporal lag (the shadow lags behind a moving object), but simmering is totally eliminated. In fact moving objects have a nicer shadow edge than static objects, because static objects can reveal the individual texels even with VSM, but moving objects blur this away nicely.

I get this as a side effect of realtime GI i'm working on, and i assume it is difficult to achieve it with traditional shadow maps.

The easiest way would be to do it in screen space with temporal aliasing (which is the same idea), but i guess you can't get the filter duration long enough to be effective?

The proper way would be to render the shadows to texture maps and apply the filter there, which boils down to texture (or object) space lighting and is probably too much work for just this purpose alone.

Edit:

Hey, you could apply the temporal filter just to the shadow map itself! E.g. shadowMapTexel = shadowMapTexel * 0.95 + newValue * 0.05.

I assume this works well with VSM and would be easy to test. Let me know how it works if you try it... unpractical self shadows?

 

 

Edited by JoeJ

Share this post


Link to post
Share on other sites

 

18 hours ago, JoeJ said:

Hey, you could apply the temporal filter just to the shadow map itself! E.g. shadowMapTexel = shadowMapTexel * 0.95 + newValue * 0.05.

 

Should I add this code to the pixel shader in the first pass, render to shadow map?

This is the code I use in the shader for rendering the shadow map texture.

VS_OUTPUT VSMain( VS_INPUT Input )
{
    VS_OUTPUT Output;
    
    
    Output.vPosition = mul( Input.vPosition, g_mWorldViewProjection );

    return Output;
}


float2 PSMain (VS_OUTPUT Input) : SV_TARGET 
{
    float2 rt;
    rt.x = Input.vPosition.z;
    rt.y = rt.x * rt.x;
    return rt;
}

This is also the code I use to calculate the percent lit in the scene rendering in the variance shadow mapping.

void CalculateVarianceShadow ( in float4 vShadowTexCoord, in float4 vShadowMapTextureCoordViewSpace, int iCascade, out float fPercentLit , in float depth) 
{
    fPercentLit = 0.0f;
    // This loop could be unrolled, and texture immediate offsets could be used if the kernel size were fixed.
    // This would be a performance improvment.
            
    float2 mapDepth = 0;


    // In orderto pull the derivative out of divergent flow control we calculate the 
    // derivative off of the view space coordinates an then scale the deriviative.
    
    float3 vShadowTexCoordDDX = 
        ddx(vShadowMapTextureCoordViewSpace );
    //float3 vShadowTexCoordDDX = vShadowMapTextureCoordViewSpace;
    vShadowTexCoordDDX *= m_vCascadeScale[iCascade].xyz; 
    float3 vShadowTexCoordDDY = 
        ddy(vShadowMapTextureCoordViewSpace );
    //float3 vShadowTexCoordDDY = vShadowMapTextureCoordViewSpace;
    vShadowTexCoordDDY *= m_vCascadeScale[iCascade].xyz; 
    
    mapDepth += g_txShadow.SampleGrad( g_samShadow, vShadowTexCoord.xyz, 
                                       vShadowTexCoordDDX,
                                       vShadowTexCoordDDY);
    //mapDepth += g_txShadow.Sample(g_samShadow, vShadowTexCoord.xyz);
    // The sample instruction uses gradients for some filters.
                
    float  fAvgZ  = mapDepth.x; // Filtered z
    float  fAvgZ2 = mapDepth.y; // Filtered z-squared
    
    if ( vShadowTexCoord.w <= fAvgZ ) // We put the z value in w so that we can index the texture array with Z.
    {
        fPercentLit = 1;
    }
    else 
    {
        float variance = ( fAvgZ2 ) - ( fAvgZ * fAvgZ );
        //variance       = min( 1.0f, max( 0.0f, variance + 0.00001f ) );
        variance = min(1.0f, max(0.0f, variance + 0.00001f));
    
        float mean     = fAvgZ;
        float d        = vShadowTexCoord.w - mean; // We put the z value in w so that we can index the texture array with Z.
        float p_max    = variance / ( variance + d*d );

        // To combat light-bleeding, experiment with raising p_max to some power
        // (Try values from 0.1 to 100.0, if you like.)
        fPercentLit = pow(p_max, 2);
    }

 

Edited by Ahmed Elhamy

Share this post


Link to post
Share on other sites

This implies you do not blur the shadow map? You should, because blurring gives soft shadows and soft shadows are usually enough to make the problem acceptable (although popping of individual shadow texels is still visible).

So i'd do the temporal filter on the blurred results which requires to keep a copy of the old blurred shadow map.

Share this post


Link to post
Share on other sites

I already do blurring for the shadow map texture, below is the shader code for the blurring.

#ifndef SEPERABLE_BLUR_KERNEL_SIZE
#define SEPERABLE_BLUR_KERNEL_SIZE 3
#endif

static const int BLUR_KERNEL_BEGIN = SEPERABLE_BLUR_KERNEL_SIZE / -2; 
static const int BLUR_KERNEL_END = SEPERABLE_BLUR_KERNEL_SIZE / 2 + 1;
static const float FLOAT_BLUR_KERNEL_SIZE = (float)SEPERABLE_BLUR_KERNEL_SIZE;

cbuffer cbblurVS : register( b2)
{
    int2        g_iWidthHeight            : packoffset( c0 );
    int            g_iKernelStart          : packoffset( c0.z );
    int            g_iKernelEnd            : packoffset( c0.w );
};

//--------------------------------------------------------------------------------------
// defines
//--------------------------------------------------------------------------------------

Texture2DArray g_txShadow : register( t5 );
SamplerState g_samShadow : register( s5 );

//--------------------------------------------------------------------------------------
// Input/Output structures
//--------------------------------------------------------------------------------------

struct PSIn
{
    float4      Pos        : SV_Position;        //Position
    float2      Tex        : TEXCOORD;            //Texture coordinate
    float2      ITex    : TEXCOORD2;
};

struct VSIn
{
    uint Pos    : SV_VertexID ;
};


PSIn VSMain(VSIn inn)
{
    PSIn output;

    output.Pos.y  = -1.0f + (inn.Pos%2) * 2.0f ;
    output.Pos.x  = -1.0f + (inn.Pos/2) * 2.0f;
    output.Pos.z = .5;
    output.Pos.w = 1;
    output.Tex.x = inn.Pos/2;
    output.Tex.y = 1.0f - inn.Pos%2;
    output.ITex.x = (float)(g_iWidthHeight.x * output.Tex.x);
    output.ITex.y = (float)(g_iWidthHeight.y * output.Tex.y);
    return output;
}

//float PSDepth

//------------------------------------------------------------------------------
// Logarithmic filtering
//------------------------------------------------------------------------------

float log_conv ( float x0, float X, float y0, float Y )
{
    return (X + log(x0 + (y0 * exp(Y - X))));
}


//--------------------------------------------------------------------------------------
// Pixel shader that performs bump mapping on the final vertex
//--------------------------------------------------------------------------------------
float2 PSBlurX(PSIn input) : SV_Target
{    
  
  
    float2 dep=0;
    [unroll]for ( int x = BLUR_KERNEL_BEGIN; x < BLUR_KERNEL_END; ++x ) {
        dep += g_txShadow.Sample( g_samShadow,  float3( input.Tex.x, input.Tex.y, 0 ), int2( x,0 ) ).rg;
    }
    dep /= FLOAT_BLUR_KERNEL_SIZE;
    return dep;  
    
//    return g_txShadow.Sample(g_samShadow,  float3(input.Tex.x, input.Tex.y, 0) ).rg;
    
}

//--------------------------------------------------------------------------------------
// Pixel shader that performs bump mapping on the final vertex
//--------------------------------------------------------------------------------------
float2 PSBlurY(PSIn input) : SV_Target
{    

    
    
    float2 dep=0;
    [unroll]for ( int y = BLUR_KERNEL_BEGIN; y < BLUR_KERNEL_END; ++y ) {
        dep += g_txShadow.Sample( g_samShadow,  float3( input.Tex.x, input.Tex.y, 0 ), int2( 0,y ) ).rg;
    }
    dep /= FLOAT_BLUR_KERNEL_SIZE;
    return dep;  
    
    //return g_txShadow.Sample(g_samShadow,  float3(input.Tex.x, input.Tex.y, 0) ).rg;
}

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

  • Advertisement
  • Popular Now

  • Similar Content

    • By mister345
      Hi, I'm on Rastertek series 42, soft shadows, which uses a blur shader and runs extremely slow.
      http://www.rastertek.com/dx11tut42.html
      He obnoxiously states that there are many ways to optimize his blur shader, but gives you no idea how to do it.
      The way he does it is :
      1. Project the objects in the scene to a render target using the depth shader.
      2. Draw black and white shadows on another render target using those depth textures.
      3. Blur the black/white shadow texture produced in step 2 by 
      a) rendering it to a smaller texture
      b) vertical / horizontal blurring that texture
      c) rendering it back to a bigger texture again.
      4. Send the blurred shadow texture into the final shader, which samples its black/white values to determine light intensity.
       
      So this uses a ton of render textures, and I just added more than one light, which multiplies the render textures required.
       
      Is there any easy way I can optimize the super expensive blur shader that wouldnt require a whole new complicated system?
      Like combining any of these render textures into one for example?
       
      If you know of any easy way not requiring too many changes, please let me know, as I already had a really hard time
      understanding the way this works, so a super complicated change would be beyond my capacity. Thanks.
       
      *For reference, here is my repo, in which I have simplified his tutorial and added an additional light.
       
      https://github.com/mister51213/DX11Port_SoftShadows/tree/MultiShadows
       
    • By Matt_Aufderheide
      I have never quite been a master of the d3d9 blend modes.. I know the basic stuff, but have been trying for a while to get a multiply/add blending mode... the best I can figure out is mult2x by setting:
      SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR);
      SetRenderState(D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR);
      //this isn't quite what I want.. basically I wonder if there is a way to like multiply by any color darker than 0.5 and add by any color lighter than that..? I don't know, maybe this system is too limited...
    • By evelyn4you
      hi,
      after implementing skinning with compute shader i want to implement skinning with VertexShader Streamout method to compare performance.
      The following Thread is a discussion about it.
      Here's the recommended setup:
      Use a pass-through geometry shader (point->point), setup the streamout and set topology to point list. Draw the whole buffer with context->Draw(). This gives a 1:1 mapping of the vertices. Later bind the stream out buffer as vertex buffer. Bind the index buffer of the original mesh. draw with DrawIndexed like you would with the original mesh (or whatever draw call you had). I know the reason why a point list as input is used, because when using the normal vertex topology as input the output would be a stream of "each of his own" primitives that would blow up the vertexbuffer. I assume a indexbuffer then would be needless ?
      But how can you transform position and normal in one step when feeding the pseudo Vertex/Geometry Shader with a point list ?
      In my VertexShader i first calculate the resulting transform matrix from bone indexes(4) und weights (4) and transform position and normal with the same resulting transform Matrix.
      Do i have to run 2 passes ? One for transforming position and one for transforming normal ?
      I think it could be done better ?
      thanks for any help
       
    • By derui
      i am new to directx. i just followed some tutorials online and started to program. It had been well till i faced this problem of loading my own 3d models from 3ds max exported as .x which is supported by directx. I am using c++ on visual studio 2010 and directX9. i really tried to find help on the net but i couldn't find which can solve my problem. i don't know where exactly the problem is. i run most of samples and examples all worked well. can anyone give me the hint or solution for my problem ?
      thanks in advance!
  • Advertisement