e4s-game/gamedata/shaders/d3d11/shadow.hlsli
2026-06-18 01:18:29 +03:00

660 lines
24 KiB
HLSL

#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