e4s-sdk/gamedata/shaders/r2/shadow.h
2026-06-17 23:06:51 +03:00

234 lines
6.9 KiB
C

#ifndef SHADOW_H
#define SHADOW_H
#include "common.h"
uniform sampler s_smap : register(ps,s0); // 2D/cube shadowmap
#define KERNEL .6f
//#define USE_SJITTER
//////////////////////////////////////////////////////////////////////////////////////////
// software
//////////////////////////////////////////////////////////////////////////////////////////
half sample_sw (float2 tc, float2 shift, float depth_cmp)
{
static const float ts = KERNEL / float(SMAP_size);
tc += shift*ts;
float texsize = SMAP_size;
float offset = 0.5f/texsize;
float2 Tex00 = tc + float2(-offset, -offset);
float2 Tex01 = tc + float2(-offset, offset);
float2 Tex10 = tc + float2( offset, -offset);
float2 Tex11 = tc + float2( offset, offset);
float4 depth = float4(
depth_cmp-tex2D (s_smap, Tex00).x,
depth_cmp-tex2D (s_smap, Tex01).x,
depth_cmp-tex2D (s_smap, Tex10).x,
depth_cmp-tex2D (s_smap, Tex11).x);
half4 compare = step (depth,0);
float2 fr = frac (Tex00*texsize);
half2 ifr = half2 (1,1) - fr;
half4 fr4 = half4 (ifr.x*ifr.y, ifr.x*fr.y, fr.x*ifr.y, fr.x*fr.y);
return dot (compare, fr4);
}
half shadow_sw (float4 tc) {
float2 tc_dw = tc.xy / tc.w;
half4 s;
s.x = sample_sw (tc_dw,float2(-1,-1),tc.z);
s.y = sample_sw (tc_dw,float2(+1,-1),tc.z);
s.z = sample_sw (tc_dw,float2(-1,+1),tc.z);
s.w = sample_sw (tc_dw,float2(+1,+1),tc.z);
return dot (s, 1.h/4.h);
}
//////////////////////////////////////////////////////////////////////////////////////////
// hardware + PCF
//////////////////////////////////////////////////////////////////////////////////////////
half sample_hw_pcf (float4 tc,float4 shift){
static const float ts = KERNEL / float(SMAP_size);
#ifndef SUNSHAFTS_DYNAMIC
return tex2Dproj (s_smap,tc + tc.w*shift*ts).x;
#else // SUNSHAFTS_DYNAMIC
float4 tc2 = tc / tc.w + shift * ts;
tc2.w = 0;
return tex2Dlod(s_smap, tc2);
#endif // SUNSHAFTS_DYNAMIC
}
half shadow_hw (float4 tc) {
half s0 = sample_hw_pcf (tc,float4(-1,-1,0,0));
half s1 = sample_hw_pcf (tc,float4(+1,-1,0,0));
half s2 = sample_hw_pcf (tc,float4(-1,+1,0,0));
half s3 = sample_hw_pcf (tc,float4(+1,+1,0,0));
return (s0+s1+s2+s3)/(4.h);
}
//////////////////////////////////////////////////////////////////////////////////////////
// hardware (ATI) + DF24/Fetch4
//////////////////////////////////////////////////////////////////////////////////////////
/*
half sample_hw_f4 (float4 tc,float4 shift){
static const float ts = KERNEL / float(SMAP_size);
float4 D4 = tex2Dproj (s_smap,tc + tc.w*shift*ts);
float4 dcmp = tc.z/tc.w ;
float4 cmp = dcmp<D4 ;
return dot (cmp,1.h/4.h);
}
*/
half sample_hw_f4 (float4 tc,float4 shift){
static const float ts = KERNEL / float(SMAP_size);
float4 T4 = tc/tc.w ;
T4.xy += shift.xy*ts ;
float4 D4 = tex2D (s_smap, T4);
float4 compare = T4.z<D4 ;
float texsize = SMAP_size ;
float2 fr = frac (T4.xy * texsize);
half2 ifr = half2 (1,1) - fr;
half4 fr4 = half4 (ifr.x*ifr.y, ifr.x*fr.y, fr.x*ifr.y, fr.x*fr.y);
half4 fr4s = fr4.zywx ;
return dot (compare, fr4s) ;
// return dot (compare, 1.h/4.h) ;
}
half shadow_hw_f4 (float4 tc) {
half s0 = sample_hw_f4 (tc,float4(-1,-1,0,0));
half s1 = sample_hw_f4 (tc,float4(+1,-1,0,0));
half s2 = sample_hw_f4 (tc,float4(-1,+1,0,0));
half s3 = sample_hw_f4 (tc,float4(+1,+1,0,0));
return (s0+s1+s2+s3)/4.h;
}
//////////////////////////////////////////////////////////////////////////////////////////
// testbed
uniform sampler2D jitter0;
uniform sampler2D jitter1;
uniform sampler2D jitter2;
uniform sampler2D jitter3;
uniform half4 jitterS;
half4 test (float4 tc, half2 offset)
{
float4 tcx = float4 (tc.xy + tc.w*offset, tc.zw);
return tex2Dproj (s_smap,tcx);
}
half shadowtest (float4 tc, float4 tcJ) // jittered sampling
{
half4 r;
const float scale = (2.7f/float(SMAP_size));
half4 J0 = tex2Dproj (jitter0,tcJ)*scale;
half4 J1 = tex2Dproj (jitter1,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.h/4.h);
}
half shadowtest_sun (float4 tc, float4 tcJ) // jittered sampling
{
half4 r;
// const float scale = (2.0f/float(SMAP_size));
const float scale = (0.7f/float(SMAP_size));
float2 tc_J = frac(tc.xy/tc.w*SMAP_size/4.0f )*.5f;
half4 J0 = tex2D (jitter0,tc_J)*scale;
//half4 J1 = tex2D (jitter1,tc_J)*scale;
const float k = .5f/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.h/4.h);
}
half shadow_high (float4 tc) // jittered sampling
{
const float scale = (0.5f/float(SMAP_size));
float2 tc_J = frac(tc.xy/tc.w*SMAP_size/4.0f )*.5f;
half4 J0 = tex2D (jitter0,tc_J)*scale;
const float k = 1.f/float(SMAP_size);
half4 r;
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;
const float k1 = 1.3f/float(SMAP_size);
half4 r1;
r1.x = test (tc,-J0.xy+half2(-k1,0)).x;
r1.y = test (tc,-J0.wz+half2( 0,-k1)).y;
r1.z = test (tc,-2*J0.xy+half2( k1, 0)).z;
r1.w = test (tc,-2*J0.wz+half2( 0, k1)).x;
return ( r.x + r.y + r.z + r.w + r1.x + r1.y + r1.z + r1.w )*1.h/8.h;
}
//////////////////////////////////////////////////////////////////////////////////////////
// select hardware or software shadowmaps
//////////////////////////////////////////////////////////////////////////////////////////
#ifdef USE_HWSMAP_PCF
// D24X8+PCF
half shadow (float4 tc) { return shadow_hw (tc); }
#else
#ifdef USE_FETCH4
// DF24+Fetch4
half shadow (float4 tc) { return shadow_hw_f4(tc); }
#else
// FP32
half shadow (float4 tc) { return shadow_sw (tc); }
#endif
#endif
#ifdef USE_HWSMAP_PCF
// D24X8+PCF
half shadow_volumetric (float4 tc) { return sample_hw_pcf ( tc, float4(0,0,0,0) ); }
#else
#ifdef USE_FETCH4
// DF24+Fetch4
half shadow_volumetric (float4 tc) { return sample_hw_f4 (tc, float4(0,0,0,0)); }
#else
// FP32
half shadow_volumetric (float4 tc) { return sample_sw (tc.xy / tc.w,float2(0,0),tc.z); }
#endif
#endif
//////////////////////////////////////////////////////////////////////////////////////////
#ifdef USE_SUNMASK
uniform float3x4 m_sunmask ; // ortho-projection
half sunmask (float4 P) { //
float2 tc = mul (m_sunmask, P); //
return tex2D (s_lmap,tc).w; // A8
}
#else
half sunmask (float4 P) { return 1.h; } //
#endif
//////////////////////////////////////////////////////////////////////////////////////////
uniform float4x4 m_shadow;
#endif