#ifndef SHADOW_H #define SHADOW_H #include "common.hlsli" uniform float4x4 m_shadow; Texture2D s_smap : register(ps, t0); SamplerComparisonState smp_smap; sampler smp_jitter; Texture2D jitter0; Texture2D jitter1; #ifndef USE_ULTRA_SHADOWS #define KERNEL 0.6f #else #define KERNEL 1.0f #endif float4 sm_gather(float2 tc, int2 offset) { #ifdef SM_4_1 return s_smap.Gather(smp_nofilter, tc, offset); #else static const float scale = float(SMAP_size); float2 fc = frac(tc * scale); tc -= fc / scale; float s0 = s_smap.SampleLevel(smp_nofilter, tc, 0, offset + int2(0, 1)).x; float s1 = s_smap.SampleLevel(smp_nofilter, tc, 0, offset + int2(1, 1)).x; float s2 = s_smap.SampleLevel(smp_nofilter, tc, 0, offset + int2(1, 0)).x; float s3 = s_smap.SampleLevel(smp_nofilter, tc, 0, offset + int2(0, 0)).x; return float4(s0, s1, s2, s3); #endif } ////////////////////////////////////////////////////////////////////////////////////////// // 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; } #define GS2 3 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; } #if SUN_QUALITY >= 4 #define FILTER_SIZE 11 #define FS FILTER_SIZE #define FS2 (FILTER_SIZE / 2) static const float W2[11][11] = { { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.0f }, { 0.0f, 0.2f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.2f, 0.0f }, { 0.0f, 0.2f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.2f, 0.0f }, { 0.0f, 0.2f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.2f, 0.0f }, { 0.0f, 0.2f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.2f, 0.0f }, { 0.0f, 0.2f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.2f, 0.0f }, { 0.0f, 0.2f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.2f, 0.0f }, { 0.0f, 0.2f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.2f, 0.0f }, { 0.0f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, }; static const float W1[11][11] = { { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.2f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.2f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.2f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.2f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.2f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.2f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.2f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.2f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.2f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.2f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, }; static const float W0[11][11] = { { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f, 0.1f, 0.1f, 0.1f, 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f, 0.1f, 1.0f, 0.1f, 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f, 0.1f, 0.1f, 0.1f, 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, }; float Fw(int r, int c, float fL) { return (1.0 - fL) * (1.0 - fL) * (1.0 - fL) * W0[r][c] + 3.0f * (1.0 - fL) * (1.0 - fL) * fL * W1[r][c] + 3.0f * fL * fL * (1.0 - fL) * W2[r][c] + fL * fL * fL * 1.0f; } #define BLOCKER_FILTER_SIZE 11 #define BFS BLOCKER_FILTER_SIZE #define BFS2 (BLOCKER_FILTER_SIZE / 2) #define SUN_WIDTH 300.0f // uses gather for DX11/10.1 and visibilty encoding for DX10.0 static const float2 poissonDisk[16] = { float2( -0.94201624f, -0.39906216f ), float2( 0.94558609f, -0.76890725f ), float2( -0.094184101f, -0.92938870f ), float2( 0.34495938f, 0.29387760f ), float2( -0.91588581f, 0.45771432f ), float2( -0.81544232f, -0.87912464f ), float2( -0.38277543f, 0.27676845f ), float2( 0.97484398f, 0.75648379f ), float2( 0.44323325f, -0.97511554f ), float2( 0.53742981f, -0.47373420f ), float2( -0.26496911f, -0.41893023f ), float2( 0.79197514f, 0.19090188f ), float2( -0.24188840f, 0.99706507f ), float2( -0.81409955f, 0.91437590f ), float2( 0.19984126f, 0.78641367f ), float2( 0.14383161f, -0.14100790f ) }; #define PCSS_PIXEL 5 #define PCSS_STEP 5 #define PCSS_PIXEL_MIN 1.0f #define PCSS_SUN_WIDTH 300.f #define PCSS_NUM_SAMPLES 16 float shadow_extreme_quality( float3 tc ) { int3 uv = int3(tc.xy * float(SMAP_size), 0); float zBlock = tc.z - 0.0001f; float avgBlockerDepth = 0.f; float blockerCount = 0.f; [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.f : 0.f; blockerCount += b1; avgBlockerDepth += shadowMapDepth * b1; } } if( blockerCount < 1 || blockerCount >= 9 ) return 1.f - min(1.f, blockerCount); 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.f; [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; } float4 Fw(int r, int c) { return float4(W0[r][c], W1[r][c], W2[r][c], 1.0f); } //====================================================================================== // This shader computes the contact hardening shadow filter //====================================================================================== float shadow_extreme_quality_fused(float3 tc) { float4 s = (0.0f).xxxx; float2 stc = (SMAP_size * tc.xy) + float2(0.5, 0.5); float2 tcs = floor(stc); float2 fc; int row; int col; float w = 0.0; float avgBlockerDepth = 0; float blockerCount = 0; float fRatio; float4 v1[FS2 + 1]; float2 v0[FS2 + 1]; float2 off; fc = stc - tcs; tc.xy = tc.xy - (fc * (1.0f / SMAP_size)); // filter shadow map samples using the dynamic weights [unroll(FS)] for (row = -FS2; row <= FS2; row += 2) { for (col = -FS2; col <= FS2; col += 2) { float4 d4; #ifndef PS_4 d4 = s_smap.Gather(smp_nofilter, tc.xy + (1.0f / SMAP_size) * float2(col, row)); #else d4.w = s_smap.SampleLevel(smp_nofilter, tc.xy + (1.0f / SMAP_size) * float2(col, row), 0).x; d4.z = s_smap.SampleLevel(smp_nofilter, tc.xy + (1.0f / SMAP_size) * float2(col + 1, row), 0).x; d4.y = s_smap.SampleLevel(smp_nofilter, tc.xy + (1.0f / SMAP_size) * float2(col + 1, row + 1), 0).x; d4.x = s_smap.SampleLevel(smp_nofilter, tc.xy + (1.0f / SMAP_size) * float2(col, row + 1), 0).x; #endif float4 b4 = (tc.zzzz <= d4) ? (0.0f).xxxx : (1.0f).xxxx; v1[(col + FS2) / 2] = (tc.zzzz <= d4) ? (1.0f).xxxx : (0.0f).xxxx; blockerCount += dot(b4, (1.0).xxxx); avgBlockerDepth += dot(d4, b4); if (col == -FS2) { s += (1 - fc.y) * (v1[0].w * (Fw(row + FS2, 0) - Fw(row + FS2, 0) * fc.x) + v1[0].z * (fc.x * (Fw(row + FS2, 0) - Fw(row + FS2, 1)) + Fw(row + FS2, 1))); s += (fc.y) * (v1[0].x * (Fw(row + FS2, 0) - Fw(row + FS2, 0) * fc.x) + v1[0].y * (fc.x * (Fw(row + FS2, 0) - Fw(row + FS2, 1)) + Fw(row + FS2, 1))); if (row > -FS2) { s += (1 - fc.y) * (v0[0].x * (Fw(row + FS2 - 1, 0) - Fw(row + FS2 - 1, 0) * fc.x) + v0[0].y * (fc.x * (Fw(row + FS2 - 1, 0) - Fw(row + FS2 - 1, 1)) + Fw(row + FS2 - 1, 1))); s += (fc.y) * (v1[0].w * (Fw(row + FS2 - 1, 0) - Fw(row + FS2 - 1, 0) * fc.x) + v1[0].z * (fc.x * (Fw(row + FS2 - 1, 0) - Fw(row + FS2 - 1, 1)) + Fw(row + FS2 - 1, 1))); } } else if (col == FS2) { s += (1 - fc.y) * (v1[FS2].w * (fc.x * (Fw(row + FS2, FS - 2) - Fw(row + FS2, FS - 1)) + Fw(row + FS2, FS - 1)) + v1[FS2].z * fc.x * Fw(row + FS2, FS - 1)); s += (fc.y) * (v1[FS2].x * (fc.x * (Fw(row + FS2, FS - 2) - Fw(row + FS2, FS - 1)) + Fw(row + FS2, FS - 1)) + v1[FS2].y * fc.x * Fw(row + FS2, FS - 1)); if (row > -FS2) { s += (1 - fc.y) * (v0[FS2].x * (fc.x * (Fw(row + FS2 - 1, FS - 2) - Fw(row + FS2 - 1, FS - 1)) + Fw(row + FS2 - 1, FS - 1)) + v0[FS2].y * fc.x * Fw(row + FS2 - 1, FS - 1)); s += (fc.y) * (v1[FS2].w * (fc.x * (Fw(row + FS2 - 1, FS - 2) - Fw(row + FS2 - 1, FS - 1)) + Fw(row + FS2 - 1, FS - 1)) + v1[FS2].z * fc.x * Fw(row + FS2 - 1, FS - 1)); } } else { s += (1 - fc.y) * (v1[(col + FS2) / 2].w * (fc.x * (Fw(row + FS2, col + FS2 - 1) - Fw(row + FS2, col + FS2 + 0)) + Fw(row + FS2, col + FS2 + 0)) + v1[(col + FS2) / 2].z * (fc.x * (Fw(row + FS2, col + FS2 - 0) - Fw(row + FS2, col + FS2 + 1)) + Fw(row + FS2, col + FS2 + 1))); s += (fc.y) * (v1[(col + FS2) / 2].x * (fc.x * (Fw(row + FS2, col + FS2 - 1) - Fw(row + FS2, col + FS2 + 0)) + Fw(row + FS2, col + FS2 + 0)) + v1[(col + FS2) / 2].y * (fc.x * (Fw(row + FS2, col + FS2 - 0) - Fw(row + FS2, col + FS2 + 1)) + Fw(row + FS2, col + FS2 + 1))); if (row > -FS2) { s += (1 - fc.y) * (v0[(col + FS2) / 2].x * (fc.x * (Fw(row + FS2 - 1, col + FS2 - 1) - Fw(row + FS2 - 1, col + FS2 + 0)) + Fw(row + FS2 - 1, col + FS2 + 0)) + v0[(col + FS2) / 2].y * (fc.x * (Fw(row + FS2 - 1, col + FS2 - 0) - Fw(row + FS2 - 1, col + FS2 + 1)) + Fw(row + FS2 - 1, col + FS2 + 1))); s += (fc.y) * (v1[(col + FS2) / 2].w * (fc.x * (Fw(row + FS2 - 1, col + FS2 - 1) - Fw(row + FS2 - 1, col + FS2 + 0)) + Fw(row + FS2 - 1, col + FS2 + 0)) + v1[(col + FS2) / 2].z * (fc.x * (Fw(row + FS2 - 1, col + FS2 - 0) - Fw(row + FS2 - 1, col + FS2 + 1)) + Fw(row + FS2 - 1, col + FS2 + 1))); } } if (row != FS2) { v0[(col + FS2) / 2] = v1[(col + FS2) / 2].xy; } } } // compute ratio using formulas from PCSS if (blockerCount > 0.0) { avgBlockerDepth /= blockerCount; fRatio = saturate(((tc.z - avgBlockerDepth) * SUN_WIDTH) / avgBlockerDepth); fRatio *= fRatio; } else { fRatio = 0.0; } // sum up weights of dynamic filter matrix for (row = 0; row < FS; ++row) { for (col = 0; col < FS; ++col) { w += Fw(row, col, fRatio); } } return dot(s, float4((1.0f - fRatio) * (1.0f - fRatio) * (1.0f - fRatio), 3.0f * (1.0 - fRatio) * (1.0 - fRatio) * fRatio, 3.0f * fRatio * fRatio * (1.0 - fRatio), fRatio * fRatio * fRatio)) / w; } #endif #ifdef SM_4_1 float dx10_1_hw_hq_7x7(float3 tc) { float s = 0.0f; float2 stc = (SMAP_size * tc.xy) + float2(0.5, 0.5); float2 tcs = floor(stc); float2 fc; int row; int col; fc.xy = stc - tcs; tc.xy = tcs * (1.0 / SMAP_size); // loop over the rows for (row = -GS2; row <= GS2; row += 2) { [unroll] for (col = -GS2; col <= GS2; col += 2) { float4 v = (tc.zzzz <= s_smap.Gather(smp_nofilter, tc.xy, int2(col, row))) ? (1.0).xxxx : (0.0).xxxx; if (row == -GS2) // top row { if (col == -GS2) // left { s += dot(float4(1.0 - fc.x, 1.0, 1.0 - fc.y, (1.0 - fc.x) * (1.0 - fc.y)), v); } else if (col == GS2) // right { s += dot(float4(1.0f, fc.x, fc.x * (1.0 - fc.y), 1.0 - fc.y), v); } else // center { s += dot(float4(1.0, 1.0, 1.0 - fc.y, 1.0 - fc.y), v); } } else if (row == GS2) // bottom row { if (col == -GS2) // left { s += dot(float4((1.0 - fc.x) * fc.y, fc.y, 1.0, (1.0 - fc.x)), v); } else if (col == GS2) // right { s += dot(float4(fc.y, fc.x * fc.y, fc.x, 1.0), v); } else // center { s += dot(float4(fc.yy, 1.0, 1.0), v); } } else // center rows { if (col == -GS2) // left { s += dot(float4((1.0 - fc.x), 1.0, 1.0, (1.0 - fc.x)), v); } else if (col == GS2) // right { s += dot(float4(1.0, fc.x, fc.x, 1.0), v); } else // center { s += dot((1.0).xxxx, v); } } } } return s * (1.0 / 49.0); } #endif float dx10_0_hw_hq_7x7(float4 tc) { tc.xyz /= tc.w; float s = 0.0; float2 stc = (SMAP_size * tc.xy) + float2(0.5, 0.5); float2 tcs = floor(stc); float2 fc; fc = stc - tcs; tc.xy = tc.xy - (fc * (1.0 / SMAP_size)); float2 pwAB = ((2.0).xx - fc); float2 tcAB = (1.0 / SMAP_size).xx / pwAB; float2 tcM = (0.5 / SMAP_size).xx; float2 pwGH = ((1.0).xx + fc); float2 tcGH = (1.0 / SMAP_size) * (fc / pwGH); for (int row = -GS2; row <= GS2; row += 2) { for (int col = -GS2; col <= GS2; col += 2) { if (row == -GS2) // top row { if (col == -GS2) // left { s += (pwAB.x * pwAB.y) * s_smap.SampleCmpLevelZero(smp_smap, tc.xy + tcAB, tc.z, int2(col, row)).x; } else if (col == GS2) // right { s += (pwGH.x * pwAB.y) * s_smap.SampleCmpLevelZero(smp_smap, tc.xy + float2(tcGH.x, tcAB.y), tc.z, int2(col, row)).x; } else // center { s += (2.0 * pwAB.y) * s_smap.SampleCmpLevelZero(smp_smap, tc.xy + float2(tcM.x, tcAB.y), tc.z, int2(col, row)).x; } } else if (row == GS2) // bottom row { if (col == -GS2) // left { s += (pwAB.x * pwGH.y) * s_smap.SampleCmpLevelZero(smp_smap, tc.xy + float2(tcAB.x, tcGH.y), tc.z, int2(col, row)).x; } else if (col == GS2) // right { s += (pwGH.x * pwGH.y) * s_smap.SampleCmpLevelZero(smp_smap, tc.xy + tcGH, tc.z, int2(col, row)).x; } else // center { s += (2.0 * pwGH.y) * s_smap.SampleCmpLevelZero(smp_smap, tc.xy + float2(tcM.x, tcGH.y), tc.z, int2(col, row)).x; } } else // center rows { if (col == -GS2) // left { s += (pwAB.x * 2.0) * s_smap.SampleCmpLevelZero(smp_smap, tc.xy + float2(tcAB.x, tcM.y), tc.z, int2(col, row)).x; } else if (col == GS2) // right { s += (pwGH.x * 2.0) * s_smap.SampleCmpLevelZero(smp_smap, tc.xy + float2(tcGH.x, tcM.y), tc.z, int2(col, row)).x; } else // center { s += (2.0 * 2.0) * s_smap.SampleCmpLevelZero(smp_smap, tc.xy + tcM, tc.z, int2(col, row)).x; } } } } return s / 49.0; } float shadow_hw_hq(float4 tc) { #if SUN_QUALITY >= 4 // extreme quality return shadow_extreme_quality(tc.xyz / tc.w); #else // SUN_QUALITY<4 #ifdef SM_4_1 return dx10_1_hw_hq_7x7(tc.xyz / tc.w); #else // SM_4_1 return dx10_0_hw_hq_7x7(tc); #endif // SM_4_1 #endif // SUN_QUALITY==4 } ////////////////////////////////////////////////////////////////////////////////////////// // 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; } float shadowtest_sun(float4 tc, float4 tcJ) // jittered sampling { float4 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) * 0.5f; float4 J0 = jitter0.Sample(smp_jitter, tc_J) * scale; // float4 J1 = tex2D (jitter1,tc_J)*scale; const float k = 0.5f / float(SMAP_size); r.x = test(tc, J0.xy + float2(-k, -k)).x; r.y = test(tc, J0.wz + float2(k, -k)).y; r.z = test(tc, -J0.xy + float2(-k, k)).z; r.w = test(tc, -J0.wz + float2(k, k)).x; return dot(r, 1.0f / 4.0f); } // jittered sampling float shadow_high(float4 tc) { const float scale = (0.5f / float(SMAP_size)); float2 tc_J = frac(tc.xy / tc.w * SMAP_size / 4.0f) * .5f; float4 J0 = jitter0.Sample(smp_jitter, tc_J) * scale; const float k = 1.0f / float(SMAP_size); float4 r; r.x = test(tc, J0.xy + float2(-k, -k)).x; r.y = test(tc, J0.wz + float2(k, -k)).y; r.z = test(tc, J0.xy + float2(-k, k)).z; r.w = test(tc, J0.wz + float2(k, k)).x; const float k1 = 1.3f / float(SMAP_size); float4 r1; r1.x = test(tc, -J0.xy + float2(-k1, 0)).x; r1.y = test(tc, -J0.wz + float2(0, -k1)).y; r1.z = test(tc, -2 * J0.xy + float2(k1, 0)).z; r1.w = test(tc, -2 * J0.wz + float2(0, k1)).x; return (r.x + r.y + r.z + r.w + r1.x + r1.y + r1.z + r1.w) * 1.0f / 8.0f; } float shadow(float4 tc) { #ifdef USE_ULTRA_SHADOWS return shadow_hw_hq(tc); #else #if SUN_QUALITY >= 2 return shadow_hw(tc); #else return shadow_hw(tc); #endif #endif } float shadow_volumetric(float4 tc) { return sample_hw_pcf(tc, float4(-1, -1, 0, 0)); } // testbed float shadowtest(float4 tc, float4 tcJ) // jittered sampling { float4 r; const float scale = (2.7f / float(SMAP_size)); tcJ.xy /= tcJ.w; float4 J0 = jitter0.Sample(smp_jitter, tcJ.xy) * scale; float4 J1 = jitter1.Sample(smp_jitter, tcJ.xy) * 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); } float shadow_rain(float4 tc, float2 tcJ) // jittered sampling { float4 r; const float scale = (4.0f / float(SMAP_size)); // float4 J0 = jitter0.Sample( smp_jitter, tcJ )*scale; // float4 J1 = jitter1.Sample( smp_jitter, tcJ )*scale; 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.h / 4.h); } #ifdef USE_SUNMASK float3x4 m_sunmask; float sunmask(float4 P) { float2 tc = mul(m_sunmask, P).xy; return 0.25f + 0.75f * s_lmap.SampleLevel(smp_linear, tc, 0).w; } #else float sunmask(float4 P) { return 1.f; } #endif #endif