#ifdef HARDWARE_SHADOWS | |
#define SHADOWMAP sampler2DShadow | |
#define SHADOWCOMPARE(tex,coord) shadow2DProj(tex, coord).r | |
#else | |
#define SHADOWMAP sampler2D | |
#define SHADOWCOMPARE(tex,coord) step(coord.z, texture2DProj(tex, coord).r) | |
#endif | |
#if FILTER_MODE == 0 | |
#define GETSHADOW Shadow_DoShadowCompare | |
#define KERNEL 1.0 | |
#elif FILTER_MODE == 1 | |
#ifdef HARDWARE_SHADOWS | |
#define GETSHADOW Shadow_DoShadowCompare | |
#else | |
#define GETSHADOW Shadow_DoBilinear_2x2 | |
#endif | |
#define KERNEL 1.0 | |
#elif FILTER_MODE == 2 | |
#define GETSHADOW Shadow_DoDither_2x2 | |
#define KERNEL 1.0 | |
#elif FILTER_MODE == 3 | |
#define GETSHADOW Shadow_DoPCF | |
#define KERNEL 4.0 | |
#elif FILTER_MODE == 4 | |
#define GETSHADOW Shadow_DoPCF | |
#define KERNEL 8.0 | |
#endif | |
uniform SHADOWMAP m_ShadowMap0; | |
uniform SHADOWMAP m_ShadowMap1; | |
uniform SHADOWMAP m_ShadowMap2; | |
uniform SHADOWMAP m_ShadowMap3; | |
uniform vec4 m_Splits; | |
uniform float m_ShadowIntensity; | |
varying vec4 projCoord0; | |
varying vec4 projCoord1; | |
varying vec4 projCoord2; | |
varying vec4 projCoord3; | |
varying float shadowPosition; | |
const float texSize = 1024.0; | |
const float pixSize = 1.0 / texSize; | |
const vec2 pixSize2 = vec2(pixSize); | |
float Shadow_DoShadowCompareOffset(in SHADOWMAP tex, in vec4 projCoord, in vec2 offset){ | |
vec4 coord = vec4(projCoord.xy + offset.xy * pixSize2, projCoord.zw); | |
return SHADOWCOMPARE(tex, coord); | |
} | |
float Shadow_DoShadowCompare(in SHADOWMAP tex, vec4 projCoord){ | |
return SHADOWCOMPARE(tex, projCoord); | |
} | |
float Shadow_BorderCheck(in vec2 coord){ | |
// Fastest, "hack" method (uses 4-5 instructions) | |
vec4 t = vec4(coord.xy, 0.0, 1.0); | |
t = step(t.wwxy, t.xyzz); | |
return dot(t,t); | |
} | |
float Shadow_DoDither_2x2(in SHADOWMAP tex, in vec4 projCoord){ | |
float shadow = 0.0; | |
vec2 o = mod(floor(gl_FragCoord.xy), 2.0); | |
shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2(-1.5, 1.5) + o); | |
shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2( 0.5, 1.5) + o); | |
shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2(-1.5, -0.5) + o); | |
shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2( 0.5, -0.5) + o); | |
shadow *= 0.25 ; | |
return shadow; | |
} | |
float Shadow_DoBilinear_2x2(in SHADOWMAP tex, in vec4 projCoord){ | |
vec4 gather = vec4(0.0); | |
gather.x = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(0.0, 0.0)); | |
gather.y = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(1.0, 0.0)); | |
gather.z = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(0.0, 1.0)); | |
gather.w = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(1.0, 1.0)); | |
vec2 f = fract( projCoord.xy * texSize ); | |
vec2 mx = mix( gather.xz, gather.yw, f.x ); | |
return mix( mx.x, mx.y, f.y ); | |
} | |
float Shadow_DoPCF(in SHADOWMAP tex, in vec4 projCoord){ | |
float shadow = 0.0; | |
float bound = KERNEL * 0.5 - 0.5; | |
bound *= PCFEDGE; | |
for (float y = -bound; y <= bound; y += PCFEDGE){ | |
for (float x = -bound; x <= bound; x += PCFEDGE){ | |
shadow += clamp(Shadow_DoShadowCompareOffset(tex,projCoord,vec2(x,y)) + | |
Shadow_BorderCheck(projCoord.xy), | |
0.0, 1.0); | |
} | |
} | |
shadow = shadow / (KERNEL * KERNEL); | |
return shadow; | |
} | |
void main(){ | |
vec4 shadowPerSplit = vec4(0.0); | |
shadowPerSplit.x = GETSHADOW(m_ShadowMap0, projCoord0); | |
shadowPerSplit.y = GETSHADOW(m_ShadowMap1, projCoord1); | |
shadowPerSplit.z = GETSHADOW(m_ShadowMap2, projCoord2); | |
shadowPerSplit.w = GETSHADOW(m_ShadowMap3, projCoord3); | |
vec4 less = step( shadowPosition, m_Splits ); | |
vec4 more = vec4(1.0) - step( shadowPosition, vec4(0.0, m_Splits.xyz) ); | |
float shadow = dot(shadowPerSplit, less * more ); | |
shadow = shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity); | |
gl_FragColor = vec4(shadow, shadow, shadow, 1.0); | |
} | |