#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); }