//-------------------------------------------------------------------------------------- // Gather pattern //-------------------------------------------------------------------------------------- static float g_fHDAOZDispScale = 0.1f; // SSAO param #ifdef USE_HDAO_CODE static float g_fSSAORejectRadius = 0.43f; // SSAO param static float g_fSSAOIntensity = 0.85f; // SSAO param static float g_fSSAOAcceptRadius = 0.0001f;// SSAO param static float g_fSSAOAcceptAngle = 0.98f; // Used by the ValleyAngle function to determine shallow valleys // Gather defines #define RING_0 (1) #define RING_1 (2) #define RING_2 (3) #define NUM_RING_0_GATHERS (2) #define NUM_RING_1_GATHERS (6) #define NUM_RING_2_GATHERS (12) #if ( MSAA_SAMPLES == 2 ) #define MSAA_SAMPLE_INDEX ( 0 ) #elif ( MSAA_SAMPLES == 4 ) #define MSAA_SAMPLE_INDEX ( 3 ) #elif ( MSAA_SAMPLES == 8 ) #define MSAA_SAMPLE_INDEX ( 6 ) #else #define MSAA_SAMPLE_INDEX ( 0 ) #endif #if SSAO_QUALITY == 3 static const int g_iNumRingGathers = NUM_RING_2_GATHERS; static const int g_iNumRings = RING_2; static const int g_iNumNormals = NUM_RING_0_GATHERS; #elif SSAO_QUALITY == 2 static const int g_iNumRingGathers = NUM_RING_1_GATHERS; static const int g_iNumRings = RING_1; static const int g_iNumNormals = NUM_RING_0_GATHERS; #elif SSAO_QUALITY == 1 static const int g_iNumRingGathers = NUM_RING_0_GATHERS; static const int g_iNumRings = RING_0; static const int g_iNumNormals = 0; #endif // Ring sample pattern static const float2 g_f2SSAORingPattern[NUM_RING_2_GATHERS] = { // Ring 0 { 1, -1 }, { 0, 1 }, // Ring 1 { 0, 3 }, { 2, 1 }, { 3, -1 }, { 1, -3 }, // Ring 2 { 1, -5 }, { 3, -3 }, { 5, -1 }, { 4, 1 }, { 2, 3 }, { 0, 5 }, }; // Ring weights static const float4 g_f4SSAORingWeight[NUM_RING_2_GATHERS] = { // Ring 0 (Sum = 5.30864) { 1.00000, 0.50000, 0.44721, 0.70711 }, { 0.50000, 0.44721, 0.70711, 1.00000 }, // Ring 1 (Sum = 6.08746) { 0.30000, 0.29104, 0.37947, 0.40000 }, { 0.42426, 0.33282, 0.37947, 0.53666 }, { 0.40000, 0.30000, 0.29104, 0.37947 }, { 0.53666, 0.42426, 0.33282, 0.37947 }, // Ring 2 (Sum = 6.53067) { 0.31530, 0.29069, 0.24140, 0.25495 }, { 0.36056, 0.29069, 0.26000, 0.30641 }, { 0.26000, 0.21667, 0.21372, 0.25495 }, { 0.29069, 0.24140, 0.25495, 0.31530 }, { 0.29069, 0.26000, 0.30641, 0.36056 }, { 0.21667, 0.21372, 0.25495, 0.26000 }, }; static const float g_fRingWeightsTotal[RING_2] = { 5.30864, 11.39610, 17.92677, }; //---------------------------------------------------------------------------------------- // Helper function to Gather samples in 10.1 and 10.0 modes //---------------------------------------------------------------------------------------- float4 GatherZSamples( float2 f2TexCoord ) { float4 f4Ret; float2 f2InvRTSize = (1.0f).xx / pos_decompression_params2.xy; #ifdef USE_MSAA f4Ret.x = g_txDepth.Load( int3( f2TexCoord * g_f2RTSize, 0 ), MSAA_SAMPLE_INDEX, int2( 1,0 ) ).z; f4Ret.y = g_txDepth.Load( int3( f2TexCoord * g_f2RTSize, 0 ), MSAA_SAMPLE_INDEX, int2( 1,1 ) ).z; f4Ret.z = g_txDepth.Load( int3( f2TexCoord * g_f2RTSize, 0 ), MSAA_SAMPLE_INDEX, int2( 0,1 ) ).z; f4Ret.w = g_txDepth.Load( int3( f2TexCoord * g_f2RTSize, 0 ), MSAA_SAMPLE_INDEX, int2( 0,0 ) ).z; #else // !USE_MSAA #ifndef SM_5 f4Ret.x = g_txDepth.Load( int3( f2TexCoord * g_f2RTSize, 0 ), int2( 1,0 ) ).z; f4Ret.y = g_txDepth.Load( int3( f2TexCoord * g_f2RTSize, 0 ), int2( 1,1 ) ).z; f4Ret.z = g_txDepth.Load( int3( f2TexCoord * g_f2RTSize, 0 ), int2( 0,1 ) ).z; f4Ret.w = g_txDepth.Load( int3( f2TexCoord * g_f2RTSize, 0 ), int2( 0,0 ) ).z; #else // !SM_5 f4Ret = g_txDepth.GatherBlue( smp_nofilter, f2TexCoord ); #endif // SM_5 #endif // USE_MSAA #ifdef USE_MSAA #ifdef GBUFFER_OPTIMIZATION f4Ret.x += g_fHDAOZDispScale * g_txNormal.Load( int3( f2TexCoord * g_f2RTSize, 0 ), MSAA_SAMPLE_INDEX, int2( 1,0 ) ).x; f4Ret.y += g_fHDAOZDispScale * g_txNormal.Load( int3( f2TexCoord * g_f2RTSize, 0 ), MSAA_SAMPLE_INDEX, int2( 1,1 ) ).x; f4Ret.z += g_fHDAOZDispScale * g_txNormal.Load( int3( f2TexCoord * g_f2RTSize, 0 ), MSAA_SAMPLE_INDEX, int2( 0,1 ) ).x; f4Ret.w += g_fHDAOZDispScale * g_txNormal.Load( int3( f2TexCoord * g_f2RTSize, 0 ), MSAA_SAMPLE_INDEX, int2( 0,0 ) ).x; #else f4Ret.x += g_fHDAOZDispScale * g_txNormal.Load( int3( f2TexCoord * g_f2RTSize, 0 ), MSAA_SAMPLE_INDEX, int2( 1,0 ) ).z; f4Ret.y += g_fHDAOZDispScale * g_txNormal.Load( int3( f2TexCoord * g_f2RTSize, 0 ), MSAA_SAMPLE_INDEX, int2( 1,1 ) ).z; f4Ret.z += g_fHDAOZDispScale * g_txNormal.Load( int3( f2TexCoord * g_f2RTSize, 0 ), MSAA_SAMPLE_INDEX, int2( 0,1 ) ).z; f4Ret.w += g_fHDAOZDispScale * g_txNormal.Load( int3( f2TexCoord * g_f2RTSize, 0 ), MSAA_SAMPLE_INDEX, int2( 0,0 ) ).z; #endif #else // !USE_MSAA #ifndef SM_5 #ifdef GBUFFER_OPTIMIZATION f4Ret.x += g_fHDAOZDispScale * g_txNormal.Load( int3( f2TexCoord * g_f2RTSize, 0 ), int2( 1,0 ) ).x; f4Ret.y += g_fHDAOZDispScale * g_txNormal.Load( int3( f2TexCoord * g_f2RTSize, 0 ), int2( 1,1 ) ).x; f4Ret.z += g_fHDAOZDispScale * g_txNormal.Load( int3( f2TexCoord * g_f2RTSize, 0 ), int2( 0,1 ) ).x; f4Ret.w += g_fHDAOZDispScale * g_txNormal.Load( int3( f2TexCoord * g_f2RTSize, 0 ), int2( 0,0 ) ).x; #else f4Ret.x += g_fHDAOZDispScale * g_txNormal.Load( int3( f2TexCoord * g_f2RTSize, 0 ), int2( 1,0 ) ).z; f4Ret.y += g_fHDAOZDispScale * g_txNormal.Load( int3( f2TexCoord * g_f2RTSize, 0 ), int2( 1,1 ) ).z; f4Ret.z += g_fHDAOZDispScale * g_txNormal.Load( int3( f2TexCoord * g_f2RTSize, 0 ), int2( 0,1 ) ).z; f4Ret.w += g_fHDAOZDispScale * g_txNormal.Load( int3( f2TexCoord * g_f2RTSize, 0 ), int2( 0,0 ) ).z; #endif #else // !SM_5 #ifdef GBUFFER_OPTIMIZATION f4Ret += g_fHDAOZDispScale * g_txNormal.GatherRed( smp_nofilter, f2TexCoord ); #else f4Ret += g_fHDAOZDispScale * g_txNormal.GatherBlue( smp_nofilter, f2TexCoord ); #endif #endif // SM_5 #endif // USE_MSAA return f4Ret; } // Used by the valley angle function #define NUM_NORMAL_LOADS (4) static const int2 g_i2HDAONormalLoadPattern[NUM_NORMAL_LOADS] = { { 0, -9 }, { 6, -6 }, { 10, 0 }, { 8, 9 }, }; #ifdef SSAO_QUALITY //================================================================================================================================= // Computes the general valley angle //================================================================================================================================= float HDAOValleyAngle( uint2 u2ScreenCoord ) { float3 f3N1; float3 f3N2; float fDot; float fSummedDot = 0.0f; int2 i2MirrorPattern; int2 i2OffsetScreenCoord; int2 i2MirrorOffsetScreenCoord; #ifdef GBUFFER_OPTIMIZATION float3 N = gbuf_unpack_normal( g_txNormal.Load( int3( u2ScreenCoord, 0), MSAA_SAMPLE_INDEX ).xy ); #else float3 N = g_txNormal.Load( int3( u2ScreenCoord, 0), MSAA_SAMPLE_INDEX ).xyz; #endif for( int iNormal=0; iNormal ( g_f2RTSize - float2( 1.0f, 1.0f ) ) ) ? ( g_f2RTSize - float2( 1.0f, 1.0f ) ) : ( i2OffsetScreenCoord ); i2MirrorOffsetScreenCoord = ( i2MirrorOffsetScreenCoord > ( g_f2RTSize - float2( 1.0f, 1.0f ) ) ) ? ( g_f2RTSize - float2( 1.0f, 1.0f ) ) : ( i2MirrorOffsetScreenCoord ); i2OffsetScreenCoord = ( i2OffsetScreenCoord < 0 ) ? ( 0 ) : ( i2OffsetScreenCoord ); i2MirrorOffsetScreenCoord = ( i2MirrorOffsetScreenCoord < 0 ) ? ( 0 ) : ( i2MirrorOffsetScreenCoord ); #ifdef GBUFFER_OPTIMIZATION f3N1.xy = g_txNormal.Load( int3( i2OffsetScreenCoord, 0), MSAA_SAMPLE_INDEX ).xy; f3N1.xyz = gbuf_unpack_normal( f3N1.xy ); f3N2.xy = g_txNormal.Load( int3( i2MirrorOffsetScreenCoord, 0), MSAA_SAMPLE_INDEX ).xy; f3N2.xyz = gbuf_unpack_normal( f3N2.xy ); #else f3N1.xy = g_txNormal.Load( int3( i2OffsetScreenCoord, 0), MSAA_SAMPLE_INDEX ).xyz; f3N2.xy = g_txNormal.Load( int3( i2MirrorOffsetScreenCoord, 0), MSAA_SAMPLE_INDEX ).xyz; #endif fDot = dot( f3N1, N ); fSummedDot += ( fDot > g_fSSAOAcceptAngle ) ? ( 0.0f ) : ( 1.0f - ( abs( fDot ) * 0.25f ) ); fDot = dot( f3N2, N ); fSummedDot += ( fDot > g_fSSAOAcceptAngle ) ? ( 0.0f ) : ( 1.0f - ( abs( fDot ) * 0.25f ) ); } fSummedDot /= 8.0f; fSummedDot += 0.5f; fSummedDot = ( fSummedDot <= 0.5f ) ? ( fSummedDot / 10.0f ) : ( fSummedDot ); return fSummedDot; } #endif #ifndef USE_MSAA #ifdef GBUFFER_OPTIMIZATION float calc_hdao( float3 P, float3 N, float2 tc, float2 tcJ, float4 pos2d ) #else float calc_hdao( float3 P, float3 N, float2 tc, float2 tcJ ) #endif #else #ifdef GBUFFER_OPTIMIZATION float calc_hdao( float3 P, float3 N, float2 tc, float2 tcJ, float4 pos2d, uint iSample ) #else float calc_hdao( float3 P, float3 N, float2 tc, float2 tcJ, uint iSample) #endif #endif #ifndef SSAO_QUALITY { return 1.0f; } #else { // Locals int2 i2ScreenCoord; float2 f2ScreenCoord; float2 f2MirrorScreenCoord; float2 f2TexCoord; float2 f2MirrorTexCoord; float2 f2InvRTSize; float4 f4PosZ; float ZDisp; float3 f3D0; float3 f3D1; float4 f4Diff; float4 f4Compare[2]; float4 f4Occlusion = 0.0f; float fOcclusion = 0.0f; // Compute integer screen coord, and store off the inverse of the RT Size f2InvRTSize = (1.0f).xx / (g_f2RTSize.xy); f2ScreenCoord = tc * (g_f2RTSize.xy); i2ScreenCoord = int2( f2ScreenCoord ); // Get the general valley angle, to scale the result by float fDot = HDAOValleyAngle( i2ScreenCoord ); ZDisp = P.z + g_fHDAOZDispScale * N.z; // For Gather we need to snap the screen coords #ifndef USE_MSAA #ifdef SM_4_1 f2ScreenCoord = float2( i2ScreenCoord ); #endif #endif // Sample the center pixel for camera Z f2TexCoord = float2( f2ScreenCoord * f2InvRTSize ); // Loop through each gather location, and compare with its mirrored location [unroll]for( int iGather=0; iGather g_fSSAOAcceptRadius.xxxx ) ? ( 1.0f ) : ( 0.0f ); f4PosZ = GatherZSamples( f2MirrorTexCoord ); f4Diff = ZDisp.xxxx - f4PosZ; f4Compare[1] = ( f4Diff < g_fSSAORejectRadius.xxxx ) ? ( 1.0f ) : ( 0.0f ); f4Compare[1] *= ( f4Diff > g_fSSAOAcceptRadius.xxxx ) ? ( 1.0f ) : ( 0.0f ); f4Occlusion.xyzw += g_f4SSAORingWeight[iGather].xyzw * ( f4Compare[0].xyzw * f4Compare[1].zwxy ); } fOcclusion = dot( f4Occlusion, g_fSSAOIntensity.xxxx ) / ( 2.0f * g_fRingWeightsTotal[g_iNumRings-1] ); fOcclusion *= fDot; fOcclusion *= P.z < 0.5f ? 0.0f : lerp( 0.0f, 1.0f, saturate( P.z - 0.5f ) ); fOcclusion = 1.0f - saturate( fOcclusion ); return fOcclusion.xxxx; } #endif #endif