Divergent/mods/Shaders Look Better/gamedata/shaders/r3/shadow.h

336 lines
8.7 KiB
C

#ifndef SHADOW_H
#define SHADOW_H
#include "common.h"
//uniform sampler s_smap : register(ps,s0); // 2D/cube shadowmap
//Texture2D<float> s_smap; // 2D/cube shadowmap
// Used for RGBA texture too ?!
Texture2D s_smap : register(ps,t0); // 2D/cube shadowmap
Texture2D<float> s_smap_minmax; // 2D/cube shadowmap
#include "gather.ps"
SamplerComparisonState smp_smap; // Special comare sampler
sampler smp_jitter;
uniform float4 ssfx_shadow_bias;
Texture2D jitter0;
Texture2D jitter1;
Texture2D jitterMipped;
#ifndef USE_ULTRA_SHADOWS
#define KERNEL 0.6f
#else
#define KERNEL 1.0f
#endif
#define PCSS_PIXEL int(4)
#define PCSS_STEP int(2)
#define PCSS_PIXEL_MIN float(1.0)
#define PCSS_SUN_WIDTH float(150.0)
float modify_light( float light )
{
return ( light > 0.7 ? 1.0 : lerp( 0.0, 1.0, saturate( light / 0.7 ) ) );
}
//////////////////////////////////////////////////////////////////////////////////////////
// hardware + PCF
//////////////////////////////////////////////////////////////////////////////////////////
float sample_hw_pcf (float4 tc,float4 shift)
{
static const float ts = KERNEL / float(SMAP_size);
tc.xyz /= tc.w;
tc.xy += shift.xy * ts;
return s_smap.SampleCmpLevelZero( smp_smap, tc.xy, tc.z).x;
}
float shadow_hw( float4 tc )
{
float s0 = sample_hw_pcf( tc, float4( -1, -1, 0, 0) );
float s1 = sample_hw_pcf( tc, float4( +1, -1, 0, 0) );
float s2 = sample_hw_pcf( tc, float4( -1, +1, 0, 0) );
float s3 = sample_hw_pcf( tc, float4( +1, +1, 0, 0) );
return (s0+s1+s2+s3)/4.h;
}
#ifdef SM_MINMAX
bool cheap_reject( float3 tc, inout bool full_light )
{
float4 plane0 = sm_minmax_gather( tc.xy, int2( -1,-1 ) );
float4 plane1 = sm_minmax_gather( tc.xy, int2( 1,-1 ) );
float4 plane2 = sm_minmax_gather( tc.xy, int2( -1, 1 ) );
float4 plane3 = sm_minmax_gather( tc.xy, int2( 1, 1 ) );
bool plane = all( ( plane0 >= (0).xxxx ) * ( plane1 >= (0).xxxx ) * ( plane2 >= (0).xxxx ) * ( plane3 >= (0).xxxx ) );
[flatten] if( !plane ) // if there are no proper plane equations in the support region
{
bool no_plane = all( ( plane0 < (0).xxxx ) * ( plane1 < (0).xxxx ) * ( plane2 < (0).xxxx ) * ( plane3 < (0).xxxx ) );
float4 z = ( tc.z - 0.0005 ).xxxx;
bool reject = all( ( z > -plane0 ) * ( z > -plane1 ) * ( z > -plane2 ) * ( z > -plane3 ) );
[flatten] if( no_plane && reject )
{
full_light = false;
return true;
}
else
{
return false;
}
}
else // plane equation detected
{
// compute corrected z for texel pos
static const float scale = float( SMAP_size / 4 );
float2 fc = frac( tc.xy * scale );
float z = lerp( lerp( plane0.y, plane1.x, fc.x ), lerp( plane2.z, plane3.w, fc.x ), fc.y );
// do minmax test with new z
full_light = ( ( tc.z - 0.0001 ) <= z );
return true;
}
}
//Sunshafts
float shadow_dx10_1_sunshafts( float4 tc, float2 pos2d )
{
float3 t = tc.xyz / tc.w;
float minmax = s_smap_minmax.SampleLevel( smp_nofilter, t, 0 ).x;
bool umbra = ( ( minmax.x < 0 ) && ( t.z > -minmax.x ) );
[branch] if( umbra )
{
return 0.0;
}
else
{
return shadow_hw( tc );
}
}
#endif // SM_MINMAX
//PCSS shadows
static const float2 poissonDisk[32] = {
float2(0.0617981, 0.07294159),
float2(0.6470215, 0.7474022),
float2(-0.5987766, -0.7512833),
float2(-0.693034, 0.6913887),
float2(0.6987045, -0.6843052),
float2(-0.9402866, 0.04474335),
float2(0.8934509, 0.07369385),
float2(0.1592735, -0.9686295),
float2(-0.05664673, 0.995282),
float2(-0.1203411, -0.1301079),
float2(0.1741608, -0.1682285),
float2(-0.09369049, 0.3196758),
float2(0.185363, 0.3213367),
float2(-0.1493771, -0.3147511),
float2(0.4452095, 0.2580113),
float2(-0.1080467, -0.5329178),
float2(0.1604507, 0.5460774),
float2(-0.4037193, -0.2611179),
float2(0.5947998, -0.2146744),
float2(0.3276062, 0.9244621),
float2(-0.6518704, -0.2503952),
float2(-0.3580975, 0.2806469),
float2(0.8587891, 0.4838005),
float2(-0.1596546, -0.8791054),
float2(-0.3096867, 0.5588146),
float2(-0.5128918, 0.1448544),
float2(0.8581337, -0.424046),
float2(0.1562584, -0.5610626),
float2(-0.7647934, 0.2709858),
float2(-0.3090832, 0.9020988),
float2(0.3935608, 0.4609676),
float2(0.3929337, -0.5010948),
};
//Quality tokens --Fine
#if !defined(SUN_QUALITY)
#define PCSS_NUM_SAMPLES int(1)
#elif SUN_QUALITY==1
#define PCSS_NUM_SAMPLES int(8)
#elif SUN_QUALITY==2
#define PCSS_NUM_SAMPLES int(12)
#elif SUN_QUALITY==3
#define PCSS_NUM_SAMPLES int(20)
#elif (SUN_QUALITY==4 || SUN_QUALITY==5)
#define PCSS_NUM_SAMPLES int(32)
#endif
float shadow_pcss( float4 tc )
{
// - Small modification to fix flickering and black squares.
// - Added a extra performance option with lower SUN_QUALITY settings.
// - Extended the blocker search from 3x3 to 4x4 for better results.
// https://www.moddb.com/mods/stalker-anomaly/addons/screen-space-shaders/
tc.xyz /= tc.w;
#if SUN_QUALITY > 3 // Blocker search ( Penumbra ) and filter
int3 uv = int3(tc.xy * float(SMAP_size), 0);
float zBlock = tc.z - 0.0001;
float avgBlockerDepth = 0.0;
float blockerCount = 0.0;
[unroll]
for( int row = -PCSS_PIXEL; row <= PCSS_PIXEL; row += PCSS_STEP )
{
[unroll]
for( int col = -PCSS_PIXEL; col <= PCSS_PIXEL; col += PCSS_STEP )
{
float shadowMapDepth = s_smap.Load( uv, int2( col, row ) ).x;
float b1 = ( shadowMapDepth < zBlock ) ? 1.0 : 0.0;
blockerCount += b1;
avgBlockerDepth += shadowMapDepth * b1;
}
}
if(blockerCount < 1)
return 1.0;
avgBlockerDepth /= blockerCount;
float fRatio = saturate( ( ( tc.z - avgBlockerDepth ) * PCSS_SUN_WIDTH ) / avgBlockerDepth );
fRatio *= fRatio;
fRatio = max(PCSS_PIXEL_MIN, fRatio * float(PCSS_PIXEL)) / float(SMAP_size);
float s = 0.0;
[unroll]
for( uint i = 0; i < PCSS_NUM_SAMPLES; ++i )
{
float2 offset = poissonDisk[i] * fRatio;
s += s_smap.SampleCmpLevelZero( smp_smap, tc.xy + offset, tc.z ).x;
}
return s / PCSS_NUM_SAMPLES;
#else // No blocker search ( Penumbra ), just filter
float fRatio = 4.0f / float(SMAP_size);
float s = 0.0;
[unroll]
for( uint i = 0; i < PCSS_NUM_SAMPLES; ++i )
{
float2 offset = poissonDisk[i] * fRatio;
float test = s_smap.SampleCmpLevelZero( smp_smap, tc.xy + offset, tc.z ).x;
s += test;
}
return s / PCSS_NUM_SAMPLES;
#endif
}
//////////////////////////////////////////////////////////////////////////////////////////
// D24X8+PCF
//////////////////////////////////////////////////////////////////////////////////////////
float4 test (float4 tc, float2 offset)
{
tc.xyz /= tc.w;
tc.xy += offset;
return s_smap.SampleCmpLevelZero( smp_smap, tc.xy, tc.z).x;
}
half shadowtest_sun (float4 tc, float4 tcJ) // jittered sampling
{
half4 r;
const float scale = (0.7/float(SMAP_size));
float2 tc_J = frac(tc.xy/tc.w*SMAP_size/4.0 )*0.5;
float4 J0 = jitter0.Sample(smp_jitter,tc_J)*scale;
const float k = 0.5/float(SMAP_size);
r.x = test (tc, J0.xy+half2(-k,-k)).x;
r.y = test (tc, J0.wz+half2( k,-k)).y;
r.z = test (tc,-J0.xy+half2(-k, k)).z;
r.w = test (tc,-J0.wz+half2( k, k)).x;
return dot(r,1.0/4.0);
}
float shadow_hw_hq( float4 tc )
{
#ifdef SM_MINMAX
bool full_light = false;
bool cheap_path = cheap_reject( tc.xyz / tc.w, full_light );
[branch] if( cheap_path )
{
[branch] if( full_light == true )
return 1.0;
else
return sample_hw_pcf( tc, (0).xxxx );
}
else
{
return shadow_pcss(tc);
}
#else // SM_MINMAX
return shadow_pcss(tc);
#endif // SM_MINMAX
}
uniform float4x4 m_shadow;
#include "slb_shadow.h"
float shadow( float4 tc, float2 pos2d )
{
return SLB_Shadow(tc, pos2d);
#ifdef USE_ULTRA_SHADOWS
#ifdef SM_MINMAX
return modify_light( shadow_hw_hq( tc ) );
#else
return shadow_hw_hq( tc );
#endif
#else
return shadow_pcss(tc);
#endif
}
//////////////////////////////////////////////////////////////////////////////////////////
// testbed
float shadow_rain(float4 tc, float2 tcJ) // jittered sampling
{
float4 r;
const float scale = (4.0/float(SMAP_size));
float4 J0 = jitter0.Sample( smp_linear, tcJ )*scale;
float4 J1 = jitter1.Sample( smp_linear, tcJ )*scale;
r.x = test (tc,J0.xy).x;
r.y = test (tc,J0.wz).y;
r.z = test (tc,J1.xy).z;
r.w = test (tc,J1.wz).x;
return dot(r,1.0/4.0);
}
//////////////////////////////////////////////////////////////////////////////////////////
#ifdef USE_SUNMASK
float3x4 m_sunmask; // ortho-projection
float sunmask( float4 P )
{
float2 tc = mul( m_sunmask, P ); //
return s_lmap.SampleLevel( smp_linear, tc, 0 ).w; //Hemi map - ambient occlusion
}
#else
float sunmask( float4 P ) { return 1.0; } //
#endif
//////////////////////////////////////////////////////////////////////////////////////////
#endif