Shadow maps flickering when light moves

Started by
7 comments, last by Beosar 9 years, 1 month ago

Hi,

I have implemented shadow maps in my game, but when the sun moves, the shadows are flickering (the edges of the shadows are moving / "jumping" back and forth instead of moving slowling in one direction)...

I am still a beginner in graphics programming, so I don't know how to fix this... Do you know a good tutorial? Or do you have any hint, tip or whatever, which could help me fixing this?

This is the deferred light shader (which outputs the light intensity to a texture):


Texture2D colorTexture : register(t0);
Texture2D normalTexture : register(t1);
Texture2D positionTexture : register(t2);

Texture2D<float> pointLightTexture : register(t3);
Texture2D<float> DirectionalLightTextures[16];


static const float PI = 3.14159265f;
static const float bias = 0.0001f;


SamplerState SampleTypePoint : register(s0);
SamplerState SampleTypeClamp : register(s1);

cbuffer LightBuffer
{
    matrix DirectionalLightMatrices[16];

    float3 ambientColor;
    uint NumDirectionalLights;

    float4 diffuseColors[16];

    float4 lightDirections[16];

};

cbuffer PointLightBuffer{
    float4 pointLightPositions[256];
    float4 pointLightColors[256]; // xyz for color, w for max light distance
    uint pointLightCount;
    float3 padding4;
};


struct PixelInputType
{
    float4 position : SV_POSITION;
    float2 tex : TEXCOORD0;
};







float4 main(PixelInputType input) : SV_TARGET
{
    float4 normals;
    float4 positions;
    float lightIntensity;
    float4 OutputColor;
    float distance, distance2;
    float3 distanceVector;
    float4 pointLightShadow;
    uint i;
    float3 lightColor;
    float2 DirectionalLightTexCoords;
    float4 LightPosition;
    float Depth, LightDepth;

    normals = normalTexture.Sample(SampleTypePoint, input.tex);
    positions = positionTexture.Sample(SampleTypePoint, input.tex);

    OutputColor.rgb = ambientColor;
    OutputColor.a = 1.0f;

    if (positions.w != 0.0f){ //positions.w has been set to greater than 0.0f in other pixel shaders if this pixel doesn't belong to the sky
        
        //////////////////////////
        /// DIRECTIONAL LIGHTS ///
        //////////////////////////
        
        for (i = 0; i < NumDirectionalLights; i++){
            
            LightPosition = mul(float4(positions.xyz, 1.0f), DirectionalLightMatrices[i]);
            DirectionalLightTexCoords.x = LightPosition.x / LightPosition.w / 2.0f + 0.5f;
            DirectionalLightTexCoords.y = -LightPosition.y / LightPosition.w / 2.0f + 0.5f;

            if (DirectionalLightTexCoords.x >= 0.0f && DirectionalLightTexCoords.x <= 1.0f && DirectionalLightTexCoords.y >= 0.0f && DirectionalLightTexCoords.y <= 1.0f)
            {
                Depth = DirectionalLightTextures[i].Sample(SampleTypeClamp, DirectionalLightTexCoords);

                LightDepth = LightPosition.z / LightPosition.w;

                LightDepth -= bias;

                if (LightDepth < Depth){

                    OutputColor.rgb += (diffuseColors[i].xyz * saturate(dot(normals.xyz, lightDirections[i].xyz)));

                        
                }
            }

        }

    


        ////////////////////
        /// POINT LIGHTS ///
        ////////////////////
    
        /*lightColor=float3(0.0f,0.0f,0.0f);

        for(i=0;i<pointLightCount;i++){
            distanceVector=positions.xyz-pointLightPositions[i].xyz;
            distance2=dot(distanceVector,distanceVector);
            
            if(distance2==0.0f){
                lightColor+=pointLightColors[i].xyz;
            }
            else if(distance2 < pointLightColors[i].w*pointLightColors[i].w){    
                //TBD
             }

        }
        
        if(lightColor.r != 0.0f || lightColor.g != 0.0f || lightColor.b != 0.0f){
            lightColor=lightColor/max(lightColor.r,max(lightColor.g,lightColor.b));
        }
        */


        OutputColor.rgb=saturate(OutputColor.rgb);
        

    }
    else{
        OutputColor.rgb = ambientColor;
    }

    
    return float4(OutputColor.rgb,1.0f);
}

Should I increase the texture size of the light depth texture? I already have 8192x8192 texels, but shadows are still flickering...

Should I use point or linear sampling when sampling the depth texture?

Advertisement

If it's just the edges "shimmering", you can minimize the effect, but you can't get rid of it entirely with standard shadow mapping. To help minimize it, you can use an algorithm such as PCF that softens the shadow edges. You can also hide it more if your objects have nice textures on them, and the light difference between the shadowed and non-shadowed is lessened.

I write a bit about it here:

https://mtnphil.wordpress.com/2011/10/31/shadow-maps-for-moving-light-sources/

You can effectively eliminate it by gradually blending between the shadow at two different light positions, but of course that comes at a significantly increased cost.


Should I use point or linear sampling when sampling the depth texture?

You should use point sampling. To soften things, you can average between different shadow map comparisons from several point samples (PCF, I mentioned before). Some of the newer graphics APIs have ways to optimize this so you don't need to take many samples (for instance, for DX11, see discussion of the Gather instruction here: https://mynameismjp.wordpress.com/category/directx/ )

http://www.gamedev.net/topic/516932-how-to-eliminate-shadow-map-flickering/


http://www.gamedev.net/topic/516932-how-to-eliminate-shadow-map-flickering/

That fixes flickering for when the camera moves, not when the light moves.

Temporal antialiasing has nice side effect that it also work as noise filter. Hawhenven't found any other cheap/free solutions yet. Some games also try to hide the artifact by stopping the light movement when camera is still and only move sun when camera is also moving.

A negative mark for trying to help, without a great deal of time to do so, with a link that might give the OP some ideas.

This site is a fantastic forum of knowledge but it really does have some immature and petty members.

I currently try to implement cascaded shadow maps...

Blending between shadows of different light source positions would be nice, but I already have only 60 FPS with a GTX Titan...

I currently try to implement cascaded shadow maps...

Blending between shadows of different light source positions would be nice, but I already have only 60 FPS with a GTX Titan...

Sounds like vsync?

8192x8192 is probably too high resolution and you get undersampling artifacts. Its also 64Mega pixels of shadow maps. If you change that to 4x2048^2 its only 16Mega pixels with more uniform density. So you probably get better effective shadow map resolution for cheaper.

The resolution of the shadow depth texture seems to have nearly zero effect on the performance, so I set it to a high value to have better shadows. I will reduce it and also add a option for this in graphics settings.

Vsync is off, it's just a high view distance (relative to other voxel games).

This topic is closed to new replies.

Advertisement