123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756 |
- #ifdef SHADOWS
- #ifndef SHADOWFLOAT
- // Dupplicate to prevent include in include issues
- float unpack(vec4 color)
- {
- const vec4 bit_shift = vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0);
- return dot(color, bit_shift);
- }
- #endif
- float computeFallOff(float value, vec2 clipSpace, float frustumEdgeFalloff)
- {
- float mask = smoothstep(1.0 - frustumEdgeFalloff, 1.00000012, clamp(dot(clipSpace, clipSpace), 0., 1.));
- return mix(value, 1.0, mask);
- }
- #define inline
- float computeShadowCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, vec2 depthValues)
- {
- vec3 directionToLight = vPositionW - lightPosition;
- float depth = length(directionToLight);
- depth = (depth + depthValues.x) / (depthValues.y);
- depth = clamp(depth, 0., 1.0);
- directionToLight = normalize(directionToLight);
- directionToLight.y = -directionToLight.y;
-
- #ifndef SHADOWFLOAT
- float shadow = unpack(textureCube(shadowSampler, directionToLight));
- #else
- float shadow = textureCube(shadowSampler, directionToLight).x;
- #endif
- return depth > shadow ? darkness : 1.0;
- }
- #define inline
- float computeShadowWithPoissonSamplingCube(vec3 lightPosition, samplerCube shadowSampler, float mapSize, float darkness, vec2 depthValues)
- {
- vec3 directionToLight = vPositionW - lightPosition;
- float depth = length(directionToLight);
- depth = (depth + depthValues.x) / (depthValues.y);
- depth = clamp(depth, 0., 1.0);
- directionToLight = normalize(directionToLight);
- directionToLight.y = -directionToLight.y;
- float visibility = 1.;
- vec3 poissonDisk[4];
- poissonDisk[0] = vec3(-1.0, 1.0, -1.0);
- poissonDisk[1] = vec3(1.0, -1.0, -1.0);
- poissonDisk[2] = vec3(-1.0, -1.0, -1.0);
- poissonDisk[3] = vec3(1.0, -1.0, 1.0);
- // Poisson Sampling
- #ifndef SHADOWFLOAT
- if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[0] * mapSize)) < depth) visibility -= 0.25;
- if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[1] * mapSize)) < depth) visibility -= 0.25;
- if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[2] * mapSize)) < depth) visibility -= 0.25;
- if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[3] * mapSize)) < depth) visibility -= 0.25;
- #else
- if (textureCube(shadowSampler, directionToLight + poissonDisk[0] * mapSize).x < depth) visibility -= 0.25;
- if (textureCube(shadowSampler, directionToLight + poissonDisk[1] * mapSize).x < depth) visibility -= 0.25;
- if (textureCube(shadowSampler, directionToLight + poissonDisk[2] * mapSize).x < depth) visibility -= 0.25;
- if (textureCube(shadowSampler, directionToLight + poissonDisk[3] * mapSize).x < depth) visibility -= 0.25;
- #endif
- return min(1.0, visibility + darkness);
- }
- #define inline
- float computeShadowWithESMCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, float depthScale, vec2 depthValues)
- {
- vec3 directionToLight = vPositionW - lightPosition;
- float depth = length(directionToLight);
- depth = (depth + depthValues.x) / (depthValues.y);
- float shadowPixelDepth = clamp(depth, 0., 1.0);
- directionToLight = normalize(directionToLight);
- directionToLight.y = -directionToLight.y;
-
- #ifndef SHADOWFLOAT
- float shadowMapSample = unpack(textureCube(shadowSampler, directionToLight));
- #else
- float shadowMapSample = textureCube(shadowSampler, directionToLight).x;
- #endif
- float esm = 1.0 - clamp(exp(min(87., depthScale * shadowPixelDepth)) * shadowMapSample, 0., 1. - darkness);
- return esm;
- }
- #define inline
- float computeShadowWithCloseESMCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, float depthScale, vec2 depthValues)
- {
- vec3 directionToLight = vPositionW - lightPosition;
- float depth = length(directionToLight);
- depth = (depth + depthValues.x) / (depthValues.y);
- float shadowPixelDepth = clamp(depth, 0., 1.0);
- directionToLight = normalize(directionToLight);
- directionToLight.y = -directionToLight.y;
-
- #ifndef SHADOWFLOAT
- float shadowMapSample = unpack(textureCube(shadowSampler, directionToLight));
- #else
- float shadowMapSample = textureCube(shadowSampler, directionToLight).x;
- #endif
- float esm = clamp(exp(min(87., -depthScale * (shadowPixelDepth - shadowMapSample))), darkness, 1.);
- return esm;
- }
- #ifdef WEBGL2
- #define inline
- float computeShadowCSM(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArray shadowSampler, float darkness, float frustumEdgeFalloff)
- {
- vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
- vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
- vec3 uvLayer = vec3(uv.x, uv.y, layer);
- float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
- #ifndef SHADOWFLOAT
- float shadow = unpack(texture2D(shadowSampler, uvLayer));
- #else
- float shadow = texture2D(shadowSampler, uvLayer).x;
- #endif
- return shadowPixelDepth > shadow ? computeFallOff(darkness, clipSpace.xy, frustumEdgeFalloff) : 1.;
- }
- #endif
- #define inline
- float computeShadow(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float darkness, float frustumEdgeFalloff)
- {
- vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
- vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
- if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
- {
- return 1.0;
- }
- else
- {
- float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
- #ifndef SHADOWFLOAT
- float shadow = unpack(texture2D(shadowSampler, uv));
- #else
- float shadow = texture2D(shadowSampler, uv).x;
- #endif
- return shadowPixelDepth > shadow ? computeFallOff(darkness, clipSpace.xy, frustumEdgeFalloff) : 1.;
- }
- }
- #define inline
- float computeShadowWithPoissonSampling(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float mapSize, float darkness, float frustumEdgeFalloff)
- {
- vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
- vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
- if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
- {
- return 1.0;
- }
- else
- {
- float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
- float visibility = 1.;
- vec2 poissonDisk[4];
- poissonDisk[0] = vec2(-0.94201624, -0.39906216);
- poissonDisk[1] = vec2(0.94558609, -0.76890725);
- poissonDisk[2] = vec2(-0.094184101, -0.92938870);
- poissonDisk[3] = vec2(0.34495938, 0.29387760);
- // Poisson Sampling
- #ifndef SHADOWFLOAT
- if (unpack(texture2D(shadowSampler, uv + poissonDisk[0] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
- if (unpack(texture2D(shadowSampler, uv + poissonDisk[1] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
- if (unpack(texture2D(shadowSampler, uv + poissonDisk[2] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
- if (unpack(texture2D(shadowSampler, uv + poissonDisk[3] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
- #else
- if (texture2D(shadowSampler, uv + poissonDisk[0] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
- if (texture2D(shadowSampler, uv + poissonDisk[1] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
- if (texture2D(shadowSampler, uv + poissonDisk[2] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
- if (texture2D(shadowSampler, uv + poissonDisk[3] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
- #endif
- return computeFallOff(min(1.0, visibility + darkness), clipSpace.xy, frustumEdgeFalloff);
- }
- }
- #define inline
- float computeShadowWithESM(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float darkness, float depthScale, float frustumEdgeFalloff)
- {
- vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
- vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
- if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
- {
- return 1.0;
- }
- else
- {
- float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
- #ifndef SHADOWFLOAT
- float shadowMapSample = unpack(texture2D(shadowSampler, uv));
- #else
- float shadowMapSample = texture2D(shadowSampler, uv).x;
- #endif
-
- float esm = 1.0 - clamp(exp(min(87., depthScale * shadowPixelDepth)) * shadowMapSample, 0., 1. - darkness);
- return computeFallOff(esm, clipSpace.xy, frustumEdgeFalloff);
- }
- }
- #define inline
- float computeShadowWithCloseESM(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float darkness, float depthScale, float frustumEdgeFalloff)
- {
- vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
- vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
- if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
- {
- return 1.0;
- }
- else
- {
- float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
-
- #ifndef SHADOWFLOAT
- float shadowMapSample = unpack(texture2D(shadowSampler, uv));
- #else
- float shadowMapSample = texture2D(shadowSampler, uv).x;
- #endif
-
- float esm = clamp(exp(min(87., -depthScale * (shadowPixelDepth - shadowMapSample))), darkness, 1.);
- return computeFallOff(esm, clipSpace.xy, frustumEdgeFalloff);
- }
- }
- #ifdef WEBGL2
- #define GREATEST_LESS_THAN_ONE 0.99999994
- // Shadow PCF kernel size 1 with a single tap (lowest quality)
- #define inline
- float computeShadowWithCSMPCF1(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArrayShadow shadowSampler, float darkness, float frustumEdgeFalloff)
- {
- vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
- vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
- uvDepth.z = clamp(uvDepth.z, 0., GREATEST_LESS_THAN_ONE);
- vec4 uvDepthLayer = vec4(uvDepth.x, uvDepth.y, layer, uvDepth.z);
- float shadow = texture(shadowSampler, uvDepthLayer);
- shadow = mix(darkness, 1., shadow);
- return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
- }
- // Shadow PCF kernel 3*3 in only 4 taps (medium quality)
- // This uses a well distributed taps to allow a gaussian distribution covering a 3*3 kernel
- // https://mynameismjp.wordpress.com/2013/09/10/shadow-maps/
- #define inline
- float computeShadowWithCSMPCF3(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArrayShadow shadowSampler, vec2 shadowMapSizeAndInverse, float darkness, float frustumEdgeFalloff)
- {
- vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
- vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
- uvDepth.z = clamp(uvDepth.z, 0., GREATEST_LESS_THAN_ONE);
- vec2 uv = uvDepth.xy * shadowMapSizeAndInverse.x; // uv in texel units
- uv += 0.5; // offset of half to be in the center of the texel
- vec2 st = fract(uv); // how far from the center
- vec2 base_uv = floor(uv) - 0.5; // texel coord
- base_uv *= shadowMapSizeAndInverse.y; // move back to uv coords
- // Equation resolved to fit in a 3*3 distribution like
- // 1 2 1
- // 2 4 2
- // 1 2 1
- vec2 uvw0 = 3. - 2. * st;
- vec2 uvw1 = 1. + 2. * st;
- vec2 u = vec2((2. - st.x) / uvw0.x - 1., st.x / uvw1.x + 1.) * shadowMapSizeAndInverse.y;
- vec2 v = vec2((2. - st.y) / uvw0.y - 1., st.y / uvw1.y + 1.) * shadowMapSizeAndInverse.y;
- float shadow = 0.;
- shadow += uvw0.x * uvw0.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[0], v[0]), layer, uvDepth.z));
- shadow += uvw1.x * uvw0.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[1], v[0]), layer, uvDepth.z));
- shadow += uvw0.x * uvw1.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[0], v[1]), layer, uvDepth.z));
- shadow += uvw1.x * uvw1.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[1], v[1]), layer, uvDepth.z));
- shadow = shadow / 16.;
- shadow = mix(darkness, 1., shadow);
- return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
- }
- // Shadow PCF kernel 5*5 in only 9 taps (high quality)
- // This uses a well distributed taps to allow a gaussian distribution covering a 5*5 kernel
- // https://mynameismjp.wordpress.com/2013/09/10/shadow-maps/
- #define inline
- float computeShadowWithCSMPCF5(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArrayShadow shadowSampler, vec2 shadowMapSizeAndInverse, float darkness, float frustumEdgeFalloff)
- {
- vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
- vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
- uvDepth.z = clamp(uvDepth.z, 0., GREATEST_LESS_THAN_ONE);
- vec2 uv = uvDepth.xy * shadowMapSizeAndInverse.x; // uv in texel units
- uv += 0.5; // offset of half to be in the center of the texel
- vec2 st = fract(uv); // how far from the center
- vec2 base_uv = floor(uv) - 0.5; // texel coord
- base_uv *= shadowMapSizeAndInverse.y; // move back to uv coords
- // Equation resolved to fit in a 5*5 distribution like
- // 1 2 4 2 1
- vec2 uvw0 = 4. - 3. * st;
- vec2 uvw1 = vec2(7.);
- vec2 uvw2 = 1. + 3. * st;
- vec3 u = vec3((3. - 2. * st.x) / uvw0.x - 2., (3. + st.x) / uvw1.x, st.x / uvw2.x + 2.) * shadowMapSizeAndInverse.y;
- vec3 v = vec3((3. - 2. * st.y) / uvw0.y - 2., (3. + st.y) / uvw1.y, st.y / uvw2.y + 2.) * shadowMapSizeAndInverse.y;
- float shadow = 0.;
- shadow += uvw0.x * uvw0.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[0], v[0]), layer, uvDepth.z));
- shadow += uvw1.x * uvw0.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[1], v[0]), layer, uvDepth.z));
- shadow += uvw2.x * uvw0.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[2], v[0]), layer, uvDepth.z));
- shadow += uvw0.x * uvw1.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[0], v[1]), layer, uvDepth.z));
- shadow += uvw1.x * uvw1.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[1], v[1]), layer, uvDepth.z));
- shadow += uvw2.x * uvw1.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[2], v[1]), layer, uvDepth.z));
- shadow += uvw0.x * uvw2.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[0], v[2]), layer, uvDepth.z));
- shadow += uvw1.x * uvw2.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[1], v[2]), layer, uvDepth.z));
- shadow += uvw2.x * uvw2.y * texture2D(shadowSampler, vec4(base_uv.xy + vec2(u[2], v[2]), layer, uvDepth.z));
- shadow = shadow / 144.;
- shadow = mix(darkness, 1., shadow);
- return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
- }
- // Shadow PCF kernel size 1 with a single tap (lowest quality)
- #define inline
- float computeShadowWithPCF1(vec4 vPositionFromLight, float depthMetric, sampler2DShadow shadowSampler, float darkness, float frustumEdgeFalloff)
- {
- if (depthMetric > 1.0 || depthMetric < 0.0) {
- return 1.0;
- }
- else
- {
- vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
- vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
- float shadow = texture2D(shadowSampler, uvDepth);
- shadow = mix(darkness, 1., shadow);
- return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
- }
- }
- // Shadow PCF kernel 3*3 in only 4 taps (medium quality)
- // This uses a well distributed taps to allow a gaussian distribution covering a 3*3 kernel
- // https://mynameismjp.wordpress.com/2013/09/10/shadow-maps/
- #define inline
- float computeShadowWithPCF3(vec4 vPositionFromLight, float depthMetric, sampler2DShadow shadowSampler, vec2 shadowMapSizeAndInverse, float darkness, float frustumEdgeFalloff)
- {
- if (depthMetric > 1.0 || depthMetric < 0.0) {
- return 1.0;
- }
- else
- {
- vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
- vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
- vec2 uv = uvDepth.xy * shadowMapSizeAndInverse.x; // uv in texel units
- uv += 0.5; // offset of half to be in the center of the texel
- vec2 st = fract(uv); // how far from the center
- vec2 base_uv = floor(uv) - 0.5; // texel coord
- base_uv *= shadowMapSizeAndInverse.y; // move back to uv coords
- // Equation resolved to fit in a 3*3 distribution like
- // 1 2 1
- // 2 4 2
- // 1 2 1
- vec2 uvw0 = 3. - 2. * st;
- vec2 uvw1 = 1. + 2. * st;
- vec2 u = vec2((2. - st.x) / uvw0.x - 1., st.x / uvw1.x + 1.) * shadowMapSizeAndInverse.y;
- vec2 v = vec2((2. - st.y) / uvw0.y - 1., st.y / uvw1.y + 1.) * shadowMapSizeAndInverse.y;
- float shadow = 0.;
- shadow += uvw0.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[0]), uvDepth.z));
- shadow += uvw1.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[0]), uvDepth.z));
- shadow += uvw0.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[1]), uvDepth.z));
- shadow += uvw1.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[1]), uvDepth.z));
- shadow = shadow / 16.;
- shadow = mix(darkness, 1., shadow);
- return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
- }
- }
-
- // Shadow PCF kernel 5*5 in only 9 taps (high quality)
- // This uses a well distributed taps to allow a gaussian distribution covering a 5*5 kernel
- // https://mynameismjp.wordpress.com/2013/09/10/shadow-maps/
- #define inline
- float computeShadowWithPCF5(vec4 vPositionFromLight, float depthMetric, sampler2DShadow shadowSampler, vec2 shadowMapSizeAndInverse, float darkness, float frustumEdgeFalloff)
- {
- if (depthMetric > 1.0 || depthMetric < 0.0) {
- return 1.0;
- }
- else
- {
- vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
- vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
- vec2 uv = uvDepth.xy * shadowMapSizeAndInverse.x; // uv in texel units
- uv += 0.5; // offset of half to be in the center of the texel
- vec2 st = fract(uv); // how far from the center
- vec2 base_uv = floor(uv) - 0.5; // texel coord
- base_uv *= shadowMapSizeAndInverse.y; // move back to uv coords
- // Equation resolved to fit in a 5*5 distribution like
- // 1 2 4 2 1
- vec2 uvw0 = 4. - 3. * st;
- vec2 uvw1 = vec2(7.);
- vec2 uvw2 = 1. + 3. * st;
- vec3 u = vec3((3. - 2. * st.x) / uvw0.x - 2., (3. + st.x) / uvw1.x, st.x / uvw2.x + 2.) * shadowMapSizeAndInverse.y;
- vec3 v = vec3((3. - 2. * st.y) / uvw0.y - 2., (3. + st.y) / uvw1.y, st.y / uvw2.y + 2.) * shadowMapSizeAndInverse.y;
- float shadow = 0.;
- shadow += uvw0.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[0]), uvDepth.z));
- shadow += uvw1.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[0]), uvDepth.z));
- shadow += uvw2.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[2], v[0]), uvDepth.z));
- shadow += uvw0.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[1]), uvDepth.z));
- shadow += uvw1.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[1]), uvDepth.z));
- shadow += uvw2.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[2], v[1]), uvDepth.z));
- shadow += uvw0.x * uvw2.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[2]), uvDepth.z));
- shadow += uvw1.x * uvw2.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[2]), uvDepth.z));
- shadow += uvw2.x * uvw2.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[2], v[2]), uvDepth.z));
- shadow = shadow / 144.;
- shadow = mix(darkness, 1., shadow);
- return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
- }
- }
- const vec3 PoissonSamplers32[64] = vec3[64](
- vec3(0.06407013, 0.05409927, 0.),
- vec3(0.7366577, 0.5789394, 0.),
- vec3(-0.6270542, -0.5320278, 0.),
- vec3(-0.4096107, 0.8411095, 0.),
- vec3(0.6849564, -0.4990818, 0.),
- vec3(-0.874181, -0.04579735, 0.),
- vec3(0.9989998, 0.0009880066, 0.),
- vec3(-0.004920578, -0.9151649, 0.),
- vec3(0.1805763, 0.9747483, 0.),
- vec3(-0.2138451, 0.2635818, 0.),
- vec3(0.109845, 0.3884785, 0.),
- vec3(0.06876755, -0.3581074, 0.),
- vec3(0.374073, -0.7661266, 0.),
- vec3(0.3079132, -0.1216763, 0.),
- vec3(-0.3794335, -0.8271583, 0.),
- vec3(-0.203878, -0.07715034, 0.),
- vec3(0.5912697, 0.1469799, 0.),
- vec3(-0.88069, 0.3031784, 0.),
- vec3(0.5040108, 0.8283722, 0.),
- vec3(-0.5844124, 0.5494877, 0.),
- vec3(0.6017799, -0.1726654, 0.),
- vec3(-0.5554981, 0.1559997, 0.),
- vec3(-0.3016369, -0.3900928, 0.),
- vec3(-0.5550632, -0.1723762, 0.),
- vec3(0.925029, 0.2995041, 0.),
- vec3(-0.2473137, 0.5538505, 0.),
- vec3(0.9183037, -0.2862392, 0.),
- vec3(0.2469421, 0.6718712, 0.),
- vec3(0.3916397, -0.4328209, 0.),
- vec3(-0.03576927, -0.6220032, 0.),
- vec3(-0.04661255, 0.7995201, 0.),
- vec3(0.4402924, 0.3640312, 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.),
- vec3(0., 0., 0.)
- );
- const vec3 PoissonSamplers64[64] = vec3[64](
- vec3(-0.613392, 0.617481, 0.),
- vec3(0.170019, -0.040254, 0.),
- vec3(-0.299417, 0.791925, 0.),
- vec3(0.645680, 0.493210, 0.),
- vec3(-0.651784, 0.717887, 0.),
- vec3(0.421003, 0.027070, 0.),
- vec3(-0.817194, -0.271096, 0.),
- vec3(-0.705374, -0.668203, 0.),
- vec3(0.977050, -0.108615, 0.),
- vec3(0.063326, 0.142369, 0.),
- vec3(0.203528, 0.214331, 0.),
- vec3(-0.667531, 0.326090, 0.),
- vec3(-0.098422, -0.295755, 0.),
- vec3(-0.885922, 0.215369, 0.),
- vec3(0.566637, 0.605213, 0.),
- vec3(0.039766, -0.396100, 0.),
- vec3(0.751946, 0.453352, 0.),
- vec3(0.078707, -0.715323, 0.),
- vec3(-0.075838, -0.529344, 0.),
- vec3(0.724479, -0.580798, 0.),
- vec3(0.222999, -0.215125, 0.),
- vec3(-0.467574, -0.405438, 0.),
- vec3(-0.248268, -0.814753, 0.),
- vec3(0.354411, -0.887570, 0.),
- vec3(0.175817, 0.382366, 0.),
- vec3(0.487472, -0.063082, 0.),
- vec3(-0.084078, 0.898312, 0.),
- vec3(0.488876, -0.783441, 0.),
- vec3(0.470016, 0.217933, 0.),
- vec3(-0.696890, -0.549791, 0.),
- vec3(-0.149693, 0.605762, 0.),
- vec3(0.034211, 0.979980, 0.),
- vec3(0.503098, -0.308878, 0.),
- vec3(-0.016205, -0.872921, 0.),
- vec3(0.385784, -0.393902, 0.),
- vec3(-0.146886, -0.859249, 0.),
- vec3(0.643361, 0.164098, 0.),
- vec3(0.634388, -0.049471, 0.),
- vec3(-0.688894, 0.007843, 0.),
- vec3(0.464034, -0.188818, 0.),
- vec3(-0.440840, 0.137486, 0.),
- vec3(0.364483, 0.511704, 0.),
- vec3(0.034028, 0.325968, 0.),
- vec3(0.099094, -0.308023, 0.),
- vec3(0.693960, -0.366253, 0.),
- vec3(0.678884, -0.204688, 0.),
- vec3(0.001801, 0.780328, 0.),
- vec3(0.145177, -0.898984, 0.),
- vec3(0.062655, -0.611866, 0.),
- vec3(0.315226, -0.604297, 0.),
- vec3(-0.780145, 0.486251, 0.),
- vec3(-0.371868, 0.882138, 0.),
- vec3(0.200476, 0.494430, 0.),
- vec3(-0.494552, -0.711051, 0.),
- vec3(0.612476, 0.705252, 0.),
- vec3(-0.578845, -0.768792, 0.),
- vec3(-0.772454, -0.090976, 0.),
- vec3(0.504440, 0.372295, 0.),
- vec3(0.155736, 0.065157, 0.),
- vec3(0.391522, 0.849605, 0.),
- vec3(-0.620106, -0.328104, 0.),
- vec3(0.789239, -0.419965, 0.),
- vec3(-0.545396, 0.538133, 0.),
- vec3(-0.178564, -0.596057, 0.)
- );
- // PCSS
- // This helps to achieve a contact hardening effect on the shadow
- // It uses 16 Taps for search and a 32 PCF taps in a randomly rotating poisson sampling disc.
- // This is heavily inspired from http://developer.download.nvidia.com/shaderlibrary/docs/shadow_PCSS.pdf
- // and http://developer.download.nvidia.com/whitepapers/2008/PCSS_Integration.pdf
- #define inline
- float computeShadowWithCSMPCSS(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArray depthSampler, highp sampler2DArrayShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff, int searchTapCount, int pcfTapCount, vec3[64] poissonSamplers, vec2 lightSizeUVCorrection, float depthCorrection, float penumbraDarkness)
- {
- vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
- vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
- uvDepth.z = clamp(uvDepth.z, 0., GREATEST_LESS_THAN_ONE);
- vec4 uvDepthLayer = vec4(uvDepth.x, uvDepth.y, layer, uvDepth.z);
- float blockerDepth = 0.0;
- float sumBlockerDepth = 0.0;
- float numBlocker = 0.0;
- for (int i = 0; i < searchTapCount; i ++) {
- blockerDepth = texture(depthSampler, vec3(uvDepth.xy + (lightSizeUV * lightSizeUVCorrection * shadowMapSizeInverse * PoissonSamplers32[i].xy), layer)).r;
- if (blockerDepth < depthMetric) {
- sumBlockerDepth += blockerDepth;
- numBlocker++;
- }
- }
- if (numBlocker < 1.0) {
- return 1.0;
- }
- else
- {
- float avgBlockerDepth = sumBlockerDepth / numBlocker;
- // Offset preventing aliasing on contact.
- float AAOffset = shadowMapSizeInverse * 10.;
- // Do not dividing by z despite being physically incorrect looks better due to the limited kernel size.
- // float penumbraRatio = (depthMetric - avgBlockerDepth) / avgBlockerDepth;
- float penumbraRatio = ((depthMetric - avgBlockerDepth) * depthCorrection + AAOffset);
- vec4 filterRadius = vec4(penumbraRatio * lightSizeUV * lightSizeUVCorrection * shadowMapSizeInverse, 0., 0.);
- float random = getRand(vPositionFromLight.xy);
- float rotationAngle = random * 3.1415926;
- vec2 rotationVector = vec2(cos(rotationAngle), sin(rotationAngle));
- float shadow = 0.;
- for (int i = 0; i < pcfTapCount; i++) {
- vec4 offset = vec4(poissonSamplers[i], 0.);
- // Rotated offset.
- offset = vec4(offset.x * rotationVector.x - offset.y * rotationVector.y, offset.y * rotationVector.x + offset.x * rotationVector.y, 0., 0.);
- shadow += texture2D(shadowSampler, uvDepthLayer + offset * filterRadius);
- }
- shadow /= float(pcfTapCount);
- // Blocker distance falloff
- shadow = mix(shadow, 1., min((depthMetric - avgBlockerDepth) * depthCorrection * penumbraDarkness, 1.));
- // Apply darkness
- shadow = mix(darkness, 1., shadow);
- // Apply light frustrum fallof
- return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
- }
- }
- // PCSS
- // This helps to achieve a contact hardening effect on the shadow
- // It uses 16 Taps for search and a 32 PCF taps in a randomly rotating poisson sampling disc.
- // This is heavily inspired from http://developer.download.nvidia.com/shaderlibrary/docs/shadow_PCSS.pdf
- // and http://developer.download.nvidia.com/whitepapers/2008/PCSS_Integration.pdf
- #define inline
- float computeShadowWithPCSS(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff, int searchTapCount, int pcfTapCount, vec3[64] poissonSamplers)
- {
- if (depthMetric > 1.0 || depthMetric < 0.0) {
- return 1.0;
- }
- else
- {
- vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
- vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
- float blockerDepth = 0.0;
- float sumBlockerDepth = 0.0;
- float numBlocker = 0.0;
- for (int i = 0; i < searchTapCount; i ++) {
- blockerDepth = texture(depthSampler, uvDepth.xy + (lightSizeUV * shadowMapSizeInverse * PoissonSamplers32[i].xy)).r;
- if (blockerDepth < depthMetric) {
- sumBlockerDepth += blockerDepth;
- numBlocker++;
- }
- }
- if (numBlocker < 1.0) {
- return 1.0;
- }
- else
- {
- float avgBlockerDepth = sumBlockerDepth / numBlocker;
- // Offset preventing aliasing on contact.
- float AAOffset = shadowMapSizeInverse * 10.;
- // Do not dividing by z despite being physically incorrect looks better due to the limited kernel size.
- // float penumbraRatio = (depthMetric - avgBlockerDepth) / avgBlockerDepth;
- float penumbraRatio = ((depthMetric - avgBlockerDepth) + AAOffset);
- float filterRadius = penumbraRatio * lightSizeUV * shadowMapSizeInverse;
- float random = getRand(vPositionFromLight.xy);
- float rotationAngle = random * 3.1415926;
- vec2 rotationVector = vec2(cos(rotationAngle), sin(rotationAngle));
- float shadow = 0.;
- for (int i = 0; i < pcfTapCount; i++) {
- vec3 offset = poissonSamplers[i];
- // Rotated offset.
- offset = vec3(offset.x * rotationVector.x - offset.y * rotationVector.y, offset.y * rotationVector.x + offset.x * rotationVector.y, 0.);
- shadow += texture2D(shadowSampler, uvDepth + offset * filterRadius);
- }
- shadow /= float(pcfTapCount);
- // Blocker distance falloff
- shadow = mix(shadow, 1., depthMetric - avgBlockerDepth);
- // Apply darkness
- shadow = mix(darkness, 1., shadow);
- // Apply light frustrum fallof
- return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
- }
- }
- }
- #define inline
- float computeShadowWithPCSS16(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff)
- {
- return computeShadowWithPCSS(vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 16, 16, PoissonSamplers32);
- }
- #define inline
- float computeShadowWithPCSS32(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff)
- {
- return computeShadowWithPCSS(vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 16, 32, PoissonSamplers32);
- }
- #define inline
- float computeShadowWithPCSS64(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff)
- {
- return computeShadowWithPCSS(vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 32, 64, PoissonSamplers64);
- }
- #define inline
- float computeShadowWithCSMPCSS16(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArray depthSampler, highp sampler2DArrayShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff, vec2 lightSizeUVCorrection, float depthCorrection, float penumbraDarkness)
- {
- return computeShadowWithCSMPCSS(layer, vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 16, 16, PoissonSamplers32, lightSizeUVCorrection, depthCorrection, penumbraDarkness);
- }
- #define inline
- float computeShadowWithCSMPCSS32(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArray depthSampler, highp sampler2DArrayShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff, vec2 lightSizeUVCorrection, float depthCorrection, float penumbraDarkness)
- {
- return computeShadowWithCSMPCSS(layer, vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 16, 32, PoissonSamplers32, lightSizeUVCorrection, depthCorrection, penumbraDarkness);
- }
- #define inline
- float computeShadowWithCSMPCSS64(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArray depthSampler, highp sampler2DArrayShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff, vec2 lightSizeUVCorrection, float depthCorrection, float penumbraDarkness)
- {
- return computeShadowWithCSMPCSS(layer, vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 32, 64, PoissonSamplers64, lightSizeUVCorrection, depthCorrection, penumbraDarkness);
- }
- #endif
- #endif
|