e4s-sdk/gamedata/shaders/r3/ssao_hdao.ps
2026-06-17 23:06:51 +03:00

325 lines
No EOL
12 KiB
PostScript

//--------------------------------------------------------------------------------------
// 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<NUM_NORMAL_LOADS; iNormal++ )
{
i2MirrorPattern = g_i2HDAONormalLoadPattern[iNormal] * int2( -1, -1 );
i2OffsetScreenCoord = u2ScreenCoord + g_i2HDAONormalLoadPattern[iNormal];
i2MirrorOffsetScreenCoord = u2ScreenCoord + i2MirrorPattern;
// Clamp our test to screen coordinates
i2OffsetScreenCoord = ( i2OffsetScreenCoord > ( 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_iNumRingGathers; ++iGather )
{
f2MirrorScreenCoord = ( g_f2SSAORingPattern[iGather] + float2( 1.0f, 1.0f ) ) * float2( -1.0f, -1.0f );
#ifdef SM_4_1
f2TexCoord = float2( ( f2ScreenCoord + ( g_f2SSAORingPattern[iGather] + float2( 1.0f, 1.0f ) ) ) * f2InvRTSize );
f2MirrorTexCoord = float2( ( f2ScreenCoord + ( f2MirrorScreenCoord + float2( 1.0f, 1.0f ) ) ) * f2InvRTSize );
#else
f2TexCoord = float2( ( f2ScreenCoord + g_f2SSAORingPattern[iGather] ) * f2InvRTSize );
f2MirrorTexCoord = float2( ( f2ScreenCoord + ( f2MirrorScreenCoord ) ) * f2InvRTSize );
#endif
f4PosZ = GatherZSamples( f2TexCoord );
f4Diff = ZDisp.xxxx - f4PosZ;
f4Compare[0] = ( f4Diff < g_fSSAORejectRadius.xxxx ) ? ( 1.0f ) : ( 0.0f );
f4Compare[0] *= ( f4Diff > 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