1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
|
const float VARIANCE_SHADOW_SCALE = 1000000.0;
const float VARIANCE_SHADOW_SCALE_INV = 1.0/VARIANCE_SHADOW_SCALE;
vec2 sampleShadowMap(sampler2DArray shadow_map, vec2 uv, vec2 offset_uv, int cascade, float shadowMapSizeInv)
{
return texture(shadow_map, vec3(uv + offset_uv * shadowMapSizeInv, float(cascade))).xy;
}
float computeShadowFactor(float shadowDepth, vec2 moments, float bias)
{
float shadow = 1.0;
if((moments.x - bias) > shadowDepth)
{
// variance shadow mapping using Chebychev's Formula
float variance = moments.y * VARIANCE_SHADOW_SCALE - moments.x * moments.x;
float mD = moments.x - bias - shadowDepth;
shadow = variance / (variance + mD * mD);
shadow = clamp(shadow, 0.0, 1.0);
}
return shadow;
}
float sampleNoPCF(sampler2DArray shadow_map, float shadowDepth, int cascade, vec4 shadowUV[4])
{
return computeShadowFactor(shadowDepth, sampleShadowMap(shadow_map, shadowUV[cascade].xy, vec2(0.0, 0.0), cascade, 1.0/1024.0), 0.05);
}
float samplePoissonPCF(sampler2DArray shadow_map, float shadowDepth, int cascade, vec4 shadowUV[4], bool use_simple_pass)
{
if(cascade > 3 || cascade < 0) return 1.0;
vec2 poissonDisc[16] = vec2[](
vec2(-0.76275, -0.3432573),
vec2(-0.5226235, -0.8277544),
vec2(-0.3780261, 0.01528688),
vec2(-0.7742821, 0.4245702),
vec2(0.04196143, -0.02622231),
vec2(-0.2974772, -0.4722782),
vec2(-0.516093, 0.71495),
vec2(-0.3257416, 0.3910343),
vec2(0.2705966, 0.6670476),
vec2(0.4918377, 0.1853267),
vec2(0.4428544, -0.6251478),
vec2(-0.09204347, 0.9267113),
vec2(0.391505, -0.2558275),
vec2(0.05605913, -0.7570801),
vec2(0.81772, -0.02475523),
vec2(0.6890262, 0.5191521)
);
float maxUVOffset[4];
maxUVOffset[0] = 1.0/300.0;
maxUVOffset[1] = 1.0/250.0;
maxUVOffset[2] = 1.0/200.0;
maxUVOffset[3] = 1.0/200.0;
if (use_simple_pass) {
// internal cockpit shadows
// bias is a bit smaller to pick up on close/sharp cockpit geometry
// favors shadow over light to avoid complex geometry halos
float visibility = 1.0f;
for (int i=0; i<16; i++) {
vec2 shadow_sample = sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[i], cascade, maxUVOffset[cascade]);
// extra bias value tuned for this distance
if( ((shadow_sample.x - 0.002f) > shadowDepth) ) {
visibility -= (1.0f/16.0f);
}
}
return visibility;
} else {
// default external shadows
// bias is a bit larger to only pick up larger geometry
// favors light over shadow to avoid flickering/spotty shadows
vec2 sum = vec2(0.0f);
for (int i=0; i<16; i++) {
sum += sampleShadowMap(shadow_map, shadowUV[cascade].xy, poissonDisc[i], cascade, maxUVOffset[cascade]);
}
return computeShadowFactor(shadowDepth, sum*(1.0f/16.0f), 0.1f);
}
}
float getShadowValue(sampler2DArray shadow_map, float depth, float shadowDepth, vec4 shadowUV[4], float fardist,
float middist, float neardist, float veryneardist)
{
// Valathil's Shadows
int cascade = 4;
cascade -= int(step(depth, fardist));
cascade -= int(step(depth, middist));
cascade -= int(step(depth, neardist));
cascade -= int(step(depth, veryneardist));
float cascade_start_dist[5];
cascade_start_dist[0] = 0.0;
cascade_start_dist[1] = veryneardist;
cascade_start_dist[2] = neardist;
cascade_start_dist[3] = middist;
cascade_start_dist[4] = fardist;
if(cascade > 3 || cascade < 0) return 1.0;
bool use_simple_pass;
if (fardist < 50.0f) {
// internal cockpit shadows
use_simple_pass = true;
} else {
// default external shadows
use_simple_pass = false;
}
float dist_threshold = (cascade_start_dist[cascade+1] - cascade_start_dist[cascade])*0.2;
if(cascade_start_dist[cascade+1] - dist_threshold > depth)
return samplePoissonPCF(shadow_map, shadowDepth, cascade, shadowUV, use_simple_pass);
return mix(samplePoissonPCF(shadow_map, shadowDepth, cascade, shadowUV, use_simple_pass), samplePoissonPCF(shadow_map, shadowDepth, cascade+1, shadowUV, use_simple_pass),
smoothstep(cascade_start_dist[cascade+1] - dist_threshold, cascade_start_dist[cascade+1], depth));
}
vec4 transformToShadowMap(mat4 shadow_proj_matrix, int i, vec4 pos)
{
vec4 shadow_proj;
shadow_proj = shadow_proj_matrix * pos;
shadow_proj += 1.0;
shadow_proj *= 0.5;
shadow_proj.w = shadow_proj.z;
shadow_proj.z = float(i);
return shadow_proj;
}
|