Jump to content

  • Log In with Google      Sign In   
  • Create Account

deferred rendering with soft shadow problem


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
8 replies to this topic

#1 db123   Members   -  Reputation: 216

Like
0Likes
Like

Posted 12 April 2012 - 08:22 AM

Posted Image Posted Image
I create a program use both deferred rendering and Traditional rendering, but when i try to render a soft shadow, there is a problem about it.
it is only present to deferred rendering.
in deferred rendering, use pcf shadow map, when i keep the camera away the mesh, it looks like ok.
1.png

but when i close to the mesh, it looks very strange
2.png
3.png
4.png

first, I render the mesh to G-Buffer, it have the world position/normal/specular/diffuse.
then I render the two mesh to shadowmap, in a R32_Float Buffer.
for render the mesh, I draw a quad, and use the G-buffer and shadowmap as the shader parameters.

==
this error occur only in deferred rendering with pcf or pcss shadow map, if i use the classical shadow map, it is ok.
when i use these code in traditional rendering, it is ok too. the shdow code is just the same. the pcss shader code is the same as the PercentageCloserSoftShadows demo in Nvidia dx10 sdk.

===
I want know the reason about it.


this is the code:
//--------------------------------------------------------------------------------------
// File:    PercentageCloserSoftShadows.fx
// Author:  Louis Bavoil
// Email:   sdkfeedback@nvidia.com
//
// Copyright (c) NVIDIA Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
#include "PercentageCloserSoftShadows.fxh"
#include "Poisson.fxh"
#include "Shading.fxh"
// PRESET is defined by the app when (re)loading the fx
#if PRESET == 0
#define USE_POISSON
#define SEARCH_POISSON_COUNT 25
#define SEARCH_POISSON Poisson25
#define PCF_POISSON_COUNT 25
#define PCF_POISSON Poisson25
#elif PRESET == 1
#define USE_POISSON
#define SEARCH_POISSON_COUNT 32
#define SEARCH_POISSON Poisson32
#define PCF_POISSON_COUNT 64
#define PCF_POISSON Poisson64
#else
#define BLOCKER_SEARCH_STEP_COUNT 3
#define PCF_FILTER_STEP_COUNT 7
#endif
Texture2D<float> tDepthMap;
float2 g_LightRadiusUV;
float g_LightZNear;
float g_LightZFar;
row_major float4x4 mWorldViewProj;
row_major float4x4 mLightView;
row_major float4x4 mLightViewProj;
row_major float4x4 mLightViewProjClip2Tex;
// Using similar triangles from the surface point to the area light
float2 SearchRegionRadiusUV(float zWorld)
{
    return g_LightRadiusUV * (zWorld - g_LightZNear) / zWorld;
}
// Using similar triangles between the area light, the blocking plane and the surface point
float2 PenumbraRadiusUV(float zReceiver, float zBlocker)
{
    return g_LightRadiusUV * (zReceiver - zBlocker) / zBlocker;
}
// Project UV size to the near plane of the light
float2 ProjectToLightUV(float2 sizeUV, float zWorld)
{
    return sizeUV * g_LightZNear / zWorld;
}
// Derivatives of light-space depth with respect to texture coordinates
float2 DepthGradient(float2 uv, float z)
{
    float2 dz_duv = 0;
    float3 duvdist_dx = ddx(float3(uv,z));
    float3 duvdist_dy = ddy(float3(uv,z));
    dz_duv.x = duvdist_dy.y * duvdist_dx.z;
    dz_duv.x -= duvdist_dx.y * duvdist_dy.z;
   
    dz_duv.y = duvdist_dx.x * duvdist_dy.z;
    dz_duv.y -= duvdist_dy.x * duvdist_dx.z;
    float det = (duvdist_dx.x * duvdist_dy.y) - (duvdist_dx.y * duvdist_dy.x);
    dz_duv /= det;
    return dz_duv;
}
float BiasedZ(float z0, float2 dz_duv, float2 offset)
{
    return z0 + dot(dz_duv, offset);
}
float ZClipToZEye(float zClip)
{
return g_LightZFar*g_LightZNear / (g_LightZFar - zClip*(g_LightZFar-g_LightZNear));  
}
// Returns average blocker depth in the search region, as well as the number of found blockers.
// Blockers are defined as shadow-map samples between the surface point and the light.
void FindBlocker(out float avgBlockerDepth,
			    out float numBlockers,
			    Texture2D<float> tDepthMap,
			    float2 uv,
			    float z0,
			    float2 dz_duv,
			    float2 searchRegionRadiusUV)
{
    float blockerSum = 0;
    numBlockers = 0;
#ifdef USE_POISSON
    for ( int i = 0; i < SEARCH_POISSON_COUNT; ++i )
    {
	    float2 offset = SEARCH_POISSON[i] * searchRegionRadiusUV;
	    float shadowMapDepth = tDepthMap.SampleLevel(PointSampler, uv + offset, 0);
	    float z = BiasedZ(z0, dz_duv, offset);
	    if ( shadowMapDepth < z )
	    {
		    blockerSum += shadowMapDepth;
		    numBlockers++;
	    }
    }
#else
    float2 stepUV = searchRegionRadiusUV / BLOCKER_SEARCH_STEP_COUNT;
    for( float x = -BLOCKER_SEARCH_STEP_COUNT; x <= BLOCKER_SEARCH_STEP_COUNT; ++x )
	    for( float y = -BLOCKER_SEARCH_STEP_COUNT; y <= BLOCKER_SEARCH_STEP_COUNT; ++y )
	    {
		    float2 offset = float2( x, y ) * stepUV;
		    float shadowMapDepth = tDepthMap.SampleLevel(PointSampler, uv + offset, 0);
		    float z = BiasedZ(z0, dz_duv, offset);
		    if ( shadowMapDepth < z )
		    {
			    blockerSum += shadowMapDepth;
			    numBlockers++;
		    }
	    }
#endif
    avgBlockerDepth = blockerSum / numBlockers;
}
// Performs PCF filtering on the shadow map using multiple taps in the filter region.
float PCF_Filter( float2 uv, float z0, float2 dz_duv, float2 filterRadiusUV )
{
    float sum = 0;
   
#ifdef USE_POISSON
    for ( int i = 0; i < PCF_POISSON_COUNT; ++i )
    {
	    float2 offset = PCF_POISSON[i] * filterRadiusUV;
	    float z = BiasedZ(z0, dz_duv, offset);
	    sum += tDepthMap.SampleCmpLevelZero(PCF_Sampler, uv + offset, z);
    }
    return sum / PCF_POISSON_COUNT;
#else
    float2 stepUV = filterRadiusUV / PCF_FILTER_STEP_COUNT;
    for( float x = -PCF_FILTER_STEP_COUNT; x <= PCF_FILTER_STEP_COUNT; ++x )
	    for( float y = -PCF_FILTER_STEP_COUNT; y <= PCF_FILTER_STEP_COUNT; ++y )
	    {
		    float2 offset = float2( x, y ) * stepUV;
		    float z = BiasedZ(z0, dz_duv, offset);
		    sum += tDepthMap.SampleCmpLevelZero(PCF_Sampler, uv + offset, z);
	    }
    float numSamples = (PCF_FILTER_STEP_COUNT*2+1);
    return sum / (numSamples*numSamples);
#endif
}
float PCSS_Shadow(float2 uv, float z, float2 dz_duv, float zEye)
{
    // ------------------------
    // STEP 1: blocker search
    // ------------------------
    float avgBlockerDepth = 0;
    float numBlockers = 0;
    float2 searchRegionRadiusUV = SearchRegionRadiusUV(zEye);
    FindBlocker( avgBlockerDepth, numBlockers, tDepthMap, uv, z, dz_duv, searchRegionRadiusUV );
    // Early out if no blocker found
    if (numBlockers == 0) return 1.0;
    // ------------------------
    // STEP 2: penumbra size
    // ------------------------
    float avgBlockerDepthWorld = ZClipToZEye(avgBlockerDepth);
    float2 penumbraRadiusUV = PenumbraRadiusUV(zEye, avgBlockerDepthWorld);
    float2 filterRadiusUV = ProjectToLightUV(penumbraRadiusUV, zEye);
   
    // ------------------------
    // STEP 3: filtering
    // ------------------------
    return PCF_Filter(uv, z, dz_duv, filterRadiusUV);
}
float PCF_Shadow(float2 uv, float z, float2 dz_duv, float zEye)
{
    // Do a blocker search to enable early out
    float avgBlockerDepth = 0;
    float numBlockers = 0;
    float2 searchRegionRadiusUV = SearchRegionRadiusUV(zEye);
    FindBlocker( avgBlockerDepth, numBlockers, tDepthMap, uv, z, dz_duv, searchRegionRadiusUV );
    if (numBlockers == 0) return 1.0;
    float2 filterRadiusUV = 0.1 * g_LightRadiusUV;
    return PCF_Filter(uv, z, dz_duv, filterRadiusUV);
}
//--------------------------------------------------------------------------------------
struct Geometry_VSIn
{
    float4 WorldPos : position;
    float3 Normal   : normal;
};
struct Geometry_VSOut
{
    float4 HPosition	 : SV_Position;
    float4 WorldPos	  : texcoord0;
    float4 LightPos	  : texcoord1;
    float3 Normal	    : normal;
};
struct Z_VSOut
{
    float4 HPosition	 : SV_Position;
};
Z_VSOut LightRenderVS ( Geometry_VSIn IN )
{
    Z_VSOut OUT;
    OUT.HPosition = mul(IN.WorldPos, mLightViewProj);
    return OUT;
}
//--------------------------------------------------------------------------------------
Geometry_VSOut EyeRenderVS ( Geometry_VSIn IN )
{
    Geometry_VSOut OUT;
    OUT.HPosition = mul(IN.WorldPos, mWorldViewProj);
    OUT.WorldPos = IN.WorldPos;
    OUT.Normal = IN.Normal;
    OUT.LightPos = mul(IN.WorldPos, mLightViewProjClip2Tex);
    return OUT;
}
bool IsBlack(float3 C)
{
    return (dot(C, C) == 0);
}
float4 EyeRenderPS ( uniform bool usePCSS, Geometry_VSOut IN ) : SV_Target
{
    float2 uv = IN.LightPos.xy / IN.LightPos.w;
    float z = IN.LightPos.z / IN.LightPos.w;
    // Compute gradient using ddx/ddy before any branching
    float2 dz_duv = DepthGradient(uv, z);
    float4 color = Shade(IN.WorldPos, IN.Normal);
    if (IsBlack(color.rgb)) return color;
    // Eye-space z from the light's point of view
    float zEye = mul(IN.WorldPos, mLightView).z;
#if 0
float shadowMapDepth = tDepthMap.SampleLevel(PointSampler, uv, 0);
if( z <= shadowMapDepth )
{
  return color;
}
else
{
  return float4( 0,0,0,1);
}
#endif
    if (usePCSS)
	    return color * PCSS_Shadow(uv, z, dz_duv, zEye);
    else
	    return color * PCF_Shadow(uv, z, dz_duv, zEye);
}
//--------------------------------------------------------------------------------------
struct PostProc_VSOut
{
    float4 pos : SV_Position;
    float2 tex : TEXCOORD;
};
float4 VisTexPS ( PostProc_VSOut IN ) : SV_TARGET
{
    float z = tDepthMap.SampleLevel(PointSampler, IN.tex, 0);
    z = (ZClipToZEye(z) - g_LightZNear) / (g_LightZFar - g_LightZNear);
    return z * 10;
}
//Vertex shader that generates a full screen triangle with texcoords
//To use draw 3 vertices with primitive type triangle
PostProc_VSOut FullScreenTriVS( uint id : SV_VertexID )
{
    PostProc_VSOut output = (PostProc_VSOut)0.0f;
    output.tex = float2( (id << 1) & 2, id & 2 );
    output.pos = float4( output.tex * float2( 2.0f, -2.0f ) + float2( -1.0f, 1.0f), 0.0f, 1.0f );
    return output;
}
//--------------------------------------------------------------------------------------
technique10 PCSS
{
    pass ShadowMapPass
    {
	    SetVertexShader( CompileShader( vs_4_0, LightRenderVS() ) );
	    SetGeometryShader( NULL );
	    SetPixelShader( NULL );
	    SetRasterizerState( LightRender_RS );
	    SetDepthStencilState( ZTestLess_DS, 0x00000000 );
	    SetBlendState( NoBlending_BS, float4( 1.0f, 1.0f, 1.0f, 1.0f ), 0xffffffff );
    }
    pass VisTex
    {
	    SetVertexShader( CompileShader( vs_4_0, FullScreenTriVS() ) );
	    SetGeometryShader( NULL );
	    SetPixelShader( CompileShader( ps_4_0, VisTexPS() ) );
	    SetRasterizerState( NoMS_NoCull_RS );
	    SetDepthStencilState( NoZTest_DS, 0x00000000 );
	    SetBlendState( NoBlending_BS, float4( 1.0f, 1.0f, 1.0f, 1.0f ), 0xffffffff );
    }
    pass ZPrepass
    {
	    SetVertexShader( CompileShader( vs_4_0, EyeRenderVS() ) );
	    SetGeometryShader( NULL );
	    SetPixelShader( NULL );
	    SetRasterizerState( EyeRender_RS );
	    SetDepthStencilState( ZTestLess_DS, 0x00000000 );
	    SetBlendState( NoBlending_BS, float4( 1.0f, 1.0f, 1.0f, 1.0f ), 0xffffffff );
    }
    pass ZEqualPCSS
    {
	    SetVertexShader( CompileShader( vs_4_0, EyeRenderVS() ) );
	    SetGeometryShader( NULL );
	    SetPixelShader( CompileShader( ps_4_0, EyeRenderPS(true) ) );
	    SetRasterizerState( EyeRender_RS );
	    SetDepthStencilState( ZTestEqual_DS, 0x00000000 );
	    SetBlendState( NoBlending_BS, float4( 1.0f, 1.0f, 1.0f, 1.0f ), 0xffffffff );
    }
    pass ZEqualPCF
    {
	    SetVertexShader( CompileShader( vs_4_0, EyeRenderVS() ) );
	    SetGeometryShader( NULL );
	    SetPixelShader( CompileShader( ps_4_0, EyeRenderPS(false) ) );
	    SetRasterizerState( EyeRender_RS );
	    SetDepthStencilState( ZTestEqual_DS, 0x00000000 );
	    SetBlendState( NoBlending_BS, float4( 1.0f, 1.0f, 1.0f, 1.0f ), 0xffffffff );
    }
}

this is the Standard shadow map code :
static const float SMAP_SIZE = 1024.0f;
static const float SMAP_DX = 1.0f / SMAP_SIZE;
float StandardShadowMap( float4 projTexC )
{
// Complete projection by doing division by w.
projTexC.xyz /= projTexC.w;
    // Points outside the light volume are in shadow.
if( projTexC.x < -1.0f || projTexC.x > 1.0f ||
	 projTexC.y < -1.0f || projTexC.y > 1.0f ||
	 projTexC.z < 0.0f )
{
	 return 0.0f;
}
    // Transform from NDC space to texture space.
projTexC.x = +0.5f*projTexC.x + 0.5f;
    projTexC.y = -0.5f*projTexC.y + 0.5f;
    // Depth in NDC space.
float depth = projTexC.z;
    // Sample shadow map to get nearest depth to light.
float s0 = g_ShadowMap.Sample(PointSampler, projTexC.xy).r;
#if 1
return depth <= s0+g_ShadBias? 1.0:0.0;
#else
float s1 = g_ShadowMap.Sample(LinearSampler, projTexC.xy + float2(SMAP_DX, 0)).r;
    float s2 = g_ShadowMap.Sample(LinearSampler, projTexC.xy + float2(0, SMAP_DX)).r;
    float s3 = g_ShadowMap.Sample(LinearSampler, projTexC.xy + float2(SMAP_DX, SMAP_DX)).r;
    // Is the pixel depth <= shadow map value?
float result0 = depth <= s0 + g_ShadBias;
    float result1 = depth <= s1 + g_ShadBias;
    float result2 = depth <= s2 + g_ShadBias;
    float result3 = depth <= s3 + g_ShadBias;
    // Transform to texel space.
float2 texelPos = SMAP_SIZE*projTexC.xy;
    // Determine the interpolation amounts.
float2 t = frac( texelPos );
    // Interpolate results.
return lerp( lerp(result0, result1, t.x),
			  lerp(result2, result3, t.x), t.y);
#endif
}

this is the shader code of render the pcss shadow in traditional rendering:
float4 StaticMeshSpotLightingPCSS( HStaticMeshMaterialVSOutput Input, bool bFrontFace : SV_IsFrontFace ) : SV_TARGET
{
float4 MaskData = TryClip( Input.oTex );
#if 0
return float4( g_SpecularPower/10, g_SpecularPower/10, g_SpecularPower/10, 1.0 );
#endif
float4 vLightingColor = SpotLightingShading( Input, MaskData, bFrontFace );
if( dot( vLightingColor.rgb, vLightingColor.rgb ) == 0 )
{
  return vLightingColor;
}
// get shadow factor here.
float4 vLightViewPos = mul( Input.oWorldPos, mLightViewProj );
// return float4( vLightViewPos.z/vLightViewPos.w,vLightViewPos.z/vLightViewPos.w,vLightViewPos.z/vLightViewPos.w,1.0);

float fShadowFactor = PCSSShader( vLightViewPos );
return vLightingColor*fShadowFactor;
}

// this is the code in deferred rendering
float4 DrawDeferredSpotLightWithPCSSPixelShader( FDeferredLightingVSOutput Input ) : SV_Target0
{
FDeferredTextureData Data = SampleDeferredData( Input.oTex );
#if 0
float Powner = GetDeferredSpecularPower(Data)/10;
return float4( Powner, Powner, Powner, 1.0 );
#endif

float3 vLightingColor = DeferredSpotLighting(Data);
if( dot( vLightingColor.rgb, vLightingColor.rgb ) == 0 )
{
  return float4(vLightingColor,1.0);
}
float3 WorldPos = GetDeferredWorldPosition(Data);
float4 vLightViewPos = mul( float4(WorldPos,1.0), mLightViewProj );

float fShadowFactor = PCSSShader( vLightViewPos );
return float4( vLightingColor*fShadowFactor, 1.0 );
}

they are call the same shadow map function to compute shadow factor!Posted Image Posted Image Posted Image

Sponsor:

#2 db123   Members   -  Reputation: 216

Like
0Likes
Like

Posted 12 April 2012 - 10:34 PM

Posted Image Posted Image Posted Image Posted Image
~~~~~
SOSOSOSOSOSO
Posted Image

#3 Ashaman73   Crossbones+   -  Reputation: 7446

Like
0Likes
Like

Posted 12 April 2012 - 11:31 PM

This is one of the major problems with shadow map techniques (shadow acne), often in combination with self shadowed meshes. The reasons and solutions are multiple. Either you try to restrict it (i.e. turn off self shadowing), play around with some parameters (bais) or test some other shadowmapping algorithms like this one: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch08.html

#4 MJP   Moderators   -  Reputation: 11315

Like
0Likes
Like

Posted 12 April 2012 - 11:36 PM

If there are differences between your deferred and forward renderer, it's probably a precision issue. It seems you're storing position in 16-bit floats, which is actually pretty bad in terms of position.

#5 db123   Members   -  Reputation: 216

Like
0Likes
Like

Posted 12 April 2012 - 11:37 PM

If there are differences between your deferred and forward renderer, it's probably a precision issue. It seems you're storing position in 16-bit floats, which is actually pretty bad in terms of position.

but it works well with standard shadow map.

#6 db123   Members   -  Reputation: 216

Like
0Likes
Like

Posted 12 April 2012 - 11:39 PM

// Derivatives of light-space depth with respect to texture coordinates
float2 DepthGradient(float2 uv, float z)
{
float2 dz_duv = 0;
float3 duvdist_dx = ddx(float3(uv,z));
float3 duvdist_dy = ddy(float3(uv,z));
dz_duv.x = duvdist_dy.y * duvdist_dx.z;
dz_duv.x -= duvdist_dx.y * duvdist_dy.z;

dz_duv
.y = duvdist_dx.x * duvdist_dy.z;
dz_duv.y -= duvdist_dy.x * duvdist_dx.z;
float det = (duvdist_dx.x * duvdist_dy.y) - (duvdist_dx.y * duvdist_dy.x);
dz_duv /= det;
return dz_duv;
}
float BiasedZ(float z0, float2 dz_duv, float2 offset)
{
return z0 + dot(dz_duv, offset);
}

I think this is the primary difference between deferred rendering and forward render...
I will test it ...

#7 db123   Members   -  Reputation: 216

Like
0Likes
Like

Posted 12 April 2012 - 11:39 PM

This is one of the major problems with shadow map techniques (shadow acne), often in combination with self shadowed meshes. The reasons and solutions are multiple. Either you try to restrict it (i.e. turn off self shadowing), play around with some parameters (bais) or test some other shadowmapping algorithms like this one: http://http.develope...gems3_ch08.html

Thanks for the tip~~~

#8 Hodgman   Moderators   -  Reputation: 30370

Like
0Likes
Like

Posted 12 April 2012 - 11:48 PM

but it works well with standard shadow map.

With standard shadow mapping you usually store a 32-bit depth value. With your deferred render, you're storing three position values.

first, I render the mesh to G-Buffer, it have the world position/normal/specular/diffuse

How do you store position in the depth-buffer? Is it float-16 format? Is it world or view space?

e.g. If you're storing 16-bit view-space positions, then you'll have far less precision than a 32-bit depth map does.

#9 db123   Members   -  Reputation: 216

Like
0Likes
Like

Posted 15 April 2012 - 12:05 AM

forward renderer + standard shadow map -> ok
forward renderer + PCSS/PCF Shadow map -> ok
deferred renderer + standard shadow map -> ok
deferred renderer + PCSS or PCF shadow map -> far away ->ok
-> be close ->error!!!!Posted Image Posted Image Posted Image Posted Image




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS