123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 |
- #ifndef SHADOW_GLSLF
- #define SHADOW_GLSLF
- // #import u_csm_center_dists u_pcf_blur_radii
- // #import u_shadow_map0 u_shadow_map1 u_shadow_map2 u_shadow_map3 u_shadow_mask
- // #import v_shadow_coord0 v_shadow_coord1 v_shadow_coord2 v_shadow_coord3 \
- // v_tex_pos_clip v_pos_view
- /*==============================================================================
- VARS
- ==============================================================================*/
- #var PRECISION highp
- #var SHADOW_TEX_RES 2048.0
- #var CSM_FADE_LAST_CASCADE 0
- #var CSM_BLEND_BETWEEN_CASCADES 0
- #var SHADOW_USAGE NO_SHADOWS
- #var NUM_CAST_LAMPS 0
- #var CSM_SECTION1 0
- #var CSM_SECTION2 0
- #var CSM_SECTION3 0
- #var COMPARED_MODE 0
- #var POISSON_DISK_NUM NO_SOFT_SHADOWS
- /*============================================================================*/
- #include <std.glsl>
- #if SHADOW_USAGE == SHADOW_MASK_GENERATION || SHADOW_USAGE == SHADOW_MAPPING_BLEND
- #include <procedural.glslf>
- #endif
- #if SHADOW_USAGE == SHADOW_MASK_GENERATION || SHADOW_USAGE == SHADOW_MAPPING_BLEND
- const float SHADOW_BLUR_OFFSET = 0.1;
- const float SHADOW_FADE_OFFSET = 0.1;
- const float SINGLE_CASCADE_BORDER_INDENT = -0.01;
- const float FIRST_CASCADE_BLUR_INDENT = 0.05;
- // Poisson disk
- // NOTE: use many vec4's to prevent firefox crash on mobile devices
- # if POISSON_DISK_NUM == POISSON_X_16
- vec4 POISSON_DISK_X_0 = vec4(0.14383161, 0.34495938, -0.38277543, -0.26496911);
- vec4 POISSON_DISK_X_1 = vec4(0.53742981, 0.19984126, 0.79197514, -0.094184101);
- vec4 POISSON_DISK_X_2 = vec4(-0.94201624, -0.91588581, -0.2418884, 0.44323325);
- vec4 POISSON_DISK_X_3 = vec4(-0.81544232, 0.94558609, -0.81409955, 0.97484398);
- vec4 POISSON_DISK_Y_0 = vec4(-0.1410079, 0.2938776, 0.27676845, -0.41893023);
- vec4 POISSON_DISK_Y_1 = vec4(-0.4737342, 0.78641367, 0.19090188, -0.9293887);
- vec4 POISSON_DISK_Y_2 = vec4(-0.39906216, 0.45771432, 0.99706507, -0.97511554);
- vec4 POISSON_DISK_Y_3 = vec4(-0.87912464, -0.76890725, 0.9143759, 0.7564837);
- # elif POISSON_DISK_NUM == POISSON_X_8
- vec2 POISSON_DISK_X_0 = vec2(-0.37192261, 0.47109537);
- vec2 POISSON_DISK_X_1 = vec2(-0.6807477, 0.69048062);
- vec2 POISSON_DISK_X_2 = vec2(0.11615683, -0.91318524);
- vec2 POISSON_DISK_X_3 = vec2(0.93688596, -0.16948928);
- vec2 POISSON_DISK_Y_0 = vec2(-0.89699117, 0.74092316);
- vec2 POISSON_DISK_Y_1 = vec2(0.38263656, -0.66119884);
- vec2 POISSON_DISK_Y_2 = vec2(-0.08193062, -0.21275223);
- vec2 POISSON_DISK_Y_3 = vec2(0.05578877, 0.84225623);
- # elif POISSON_DISK_NUM == POISSON_X_4
- vec2 POISSON_DISK_X_0 = vec2(-0.51808083, 0.0);
- vec2 POISSON_DISK_X_1 = vec2(0.5741194, 0.0);
- vec2 POISSON_DISK_X_2 = vec2(-0.68048857, 0.0);
- vec2 POISSON_DISK_X_3 = vec2(0.82934988, 0.0);
- vec2 POISSON_DISK_Y_0 = vec2(0.70009436, 0.0);
- vec2 POISSON_DISK_Y_1 = vec2(-0.78790467, 0.0);
- vec2 POISSON_DISK_Y_2 = vec2(-0.58619489, 0.0);
- vec2 POISSON_DISK_Y_3 = vec2(0.41902178, 0.0);
- # endif
- bool is_tex_coords_inside(vec2 coords, float indent) {
- return all(lessThanEqual(coords, vec2(1.0 + indent)))
- && all(greaterThanEqual(coords, vec2(0.0 - indent)));
- }
- float calc_poisson_visibility(float poisson_disc_x, float poisson_disc_y,
- mat2 rotation_mat, vec3 shadow_coord, float blur_radius,
- PRECISION GLSL_SMPLR2D_SHDW shadow_map) {
- # if POISSON_DISK_NUM != NO_SOFT_SHADOWS
- vec2 coords, offset;
- offset.x = poisson_disc_x;
- offset.y = poisson_disc_y;
- offset = rotation_mat * offset;
- coords = shadow_coord.xy + offset * blur_radius / SHADOW_TEX_RES;
- # else
- vec2 coords = shadow_coord.xy;
- # endif
- # if !CSM_SECTION1
- // NOTE: fix issue with solid black border at the edge of the last cascade
- // caused by FIRST_CASCADE_BLUR_INDENT for single cascade scheme
- if (!is_tex_coords_inside(coords, SINGLE_CASCADE_BORDER_INDENT))
- return 1.0;
- # endif
- #if COMPARED_MODE
- return GLSL_TEXTURE(shadow_map, vec3(coords, shadow_coord.z));
- #else
- return step(shadow_coord.z, GLSL_TEXTURE(shadow_map, coords).r);
- #endif
- }
- float shadow_map_visibility(vec3 shadow_coord, PRECISION GLSL_SMPLR2D_SHDW shadow_map,
- float blur_radius) {
- float visibility = 0.0;
- shadow_coord.z = clamp(shadow_coord.z, 0.0, 1.0);
- #if POISSON_DISK_NUM != NO_SOFT_SHADOWS
- // Poisson disk random rotation
- float rnd_val = generate_dithering_tex(shadow_coord.xy).x * M_PI;
- float rnd_cos = cos(rnd_val);
- float rnd_sin = sin(rnd_val);
- mat2 rotation_mat = mat2(rnd_cos, rnd_sin, -rnd_sin, rnd_cos);
- for (int i = 0; i < POISSON_DISK_NUM; i++) {
- visibility += calc_poisson_visibility(POISSON_DISK_X_0[i],
- POISSON_DISK_Y_0[i], rotation_mat, shadow_coord,
- blur_radius, shadow_map);
- visibility += calc_poisson_visibility(POISSON_DISK_X_1[i],
- POISSON_DISK_Y_1[i], rotation_mat, shadow_coord,
- blur_radius, shadow_map);
- visibility += calc_poisson_visibility(POISSON_DISK_X_2[i],
- POISSON_DISK_Y_2[i], rotation_mat, shadow_coord,
- blur_radius, shadow_map);
- visibility += calc_poisson_visibility(POISSON_DISK_X_3[i],
- POISSON_DISK_Y_3[i], rotation_mat, shadow_coord,
- blur_radius, shadow_map);
- }
- return clamp(visibility / (float(POISSON_DISK_NUM) * 4.0), 0.0, 1.0);
- #else
- return calc_poisson_visibility(0.0, 0.0, mat2(0.0), shadow_coord,
- blur_radius, shadow_map);
- #endif
- }
- float shadow_map_visibility_overlap(vec3 shadow_coord0, PRECISION GLSL_SMPLR2D_SHDW shadow_map0,
- vec3 shadow_coord1, PRECISION GLSL_SMPLR2D_SHDW shadow_map1, float blur_radius0,
- float blur_radius1, float factor) {
- float vis0, vis1;
- shadow_coord0.z = clamp(shadow_coord0.z, 0.0, 1.0);
- shadow_coord1.z = clamp(shadow_coord1.z, 0.0, 1.0);
- vis0 = 0.0; vis1 = 0.0;
- #if POISSON_DISK_NUM != NO_SOFT_SHADOWS
- // Poisson disk random rotation
- float rnd_val = generate_dithering_tex(shadow_coord0.xy).x * M_PI;
- float rnd_cos = cos(rnd_val);
- float rnd_sin = sin(rnd_val);
- mat2 rotation_mat = mat2(rnd_cos, rnd_sin, -rnd_sin, rnd_cos);
- // NOTE: use different loops for sampling different shadow maps to avoid
- // some issues on systems with free drivers (e.g. Arch)
- for (int i = 0; i < POISSON_DISK_NUM; i++) {
- vis0 += calc_poisson_visibility(POISSON_DISK_X_0[i],
- POISSON_DISK_Y_0[i], rotation_mat, shadow_coord0,
- blur_radius0, shadow_map0);
- vis0 += calc_poisson_visibility(POISSON_DISK_X_1[i],
- POISSON_DISK_Y_1[i], rotation_mat, shadow_coord0,
- blur_radius0, shadow_map0);
- vis0 += calc_poisson_visibility(POISSON_DISK_X_2[i],
- POISSON_DISK_Y_2[i], rotation_mat, shadow_coord0,
- blur_radius0, shadow_map0);
- vis0 += calc_poisson_visibility(POISSON_DISK_X_3[i],
- POISSON_DISK_Y_3[i], rotation_mat, shadow_coord0,
- blur_radius0, shadow_map0);
- }
- for (int i = 0; i < POISSON_DISK_NUM; i++) {
- vis1 += calc_poisson_visibility(POISSON_DISK_X_0[i],
- POISSON_DISK_Y_0[i], rotation_mat, shadow_coord1,
- blur_radius1, shadow_map1);
- vis1 += calc_poisson_visibility(POISSON_DISK_X_1[i],
- POISSON_DISK_Y_1[i], rotation_mat, shadow_coord1,
- blur_radius1, shadow_map1);
- vis1 += calc_poisson_visibility(POISSON_DISK_X_2[i],
- POISSON_DISK_Y_2[i], rotation_mat, shadow_coord1,
- blur_radius1, shadow_map1);
- vis1 += calc_poisson_visibility(POISSON_DISK_X_3[i],
- POISSON_DISK_Y_3[i], rotation_mat, shadow_coord1,
- blur_radius1, shadow_map1);
- }
- vis0 = mix(vis0, vis1, factor);
- vis0 /= (float(POISSON_DISK_NUM) * 4.0);
- #else
- vis0 += calc_poisson_visibility(0.0, 0.0, mat2(0.0), shadow_coord0,
- blur_radius0, shadow_map0);
- vis1 += calc_poisson_visibility(0.0, 0.0, mat2(0.0), shadow_coord1,
- blur_radius1, shadow_map1);
- vis0 = mix(vis0, vis1, factor);
- #endif
- return clamp(vis0, 0.0, 1.0);
- }
- float get_edge_distance_tex(vec2 coords) {
- float a = min(coords.x, coords.y);
- float b = min(1.0 - coords.x, 1.0 - coords.y);
- return min(a, b);
- }
- float fade_shadow(float vis, float edge_dist) {
- if (edge_dist >= 0.0 && edge_dist <= SHADOW_FADE_OFFSET)
- vis = (vis - 1.0) / SHADOW_FADE_OFFSET * edge_dist + 1.0;
- return vis;
- }
- float get_visibility_blended(vec3 tex_coords0, vec3 tex_coords1,
- PRECISION GLSL_SMPLR2D_SHDW shadow_map0, PRECISION GLSL_SMPLR2D_SHDW shadow_map1,
- float blur_radius0, float blur_radius1, float center_dist, float depth) {
- float vis;
- # if CSM_BLEND_BETWEEN_CASCADES
- float edge_dist = get_edge_distance_tex(tex_coords0.xy);
- if (-depth > center_dist && edge_dist >= 0.0
- && edge_dist <= SHADOW_BLUR_OFFSET
- && is_tex_coords_inside(tex_coords1.xy, 0.0)) {
- float blend_factor = 1.0 - edge_dist / SHADOW_BLUR_OFFSET;
- vis = shadow_map_visibility_overlap(tex_coords0,
- shadow_map0, tex_coords1, shadow_map1, blur_radius0,
- blur_radius1, blend_factor);
- } else
- # endif
- vis = shadow_map_visibility(tex_coords0, shadow_map0, blur_radius0);
- return vis;
- }
- float get_visibility_faded(vec3 tex_coords, PRECISION GLSL_SMPLR2D_SHDW shadow_map,
- float blur_radius, float center_dist, float depth) {
- float vis = shadow_map_visibility(tex_coords, shadow_map, blur_radius);
- # if CSM_FADE_LAST_CASCADE
- if (-depth > center_dist) {
- float edge_dist = get_edge_distance_tex(tex_coords.xy);
- vis = fade_shadow(vis, edge_dist);
- }
- # endif
- return vis;
- }
- vec4 shadow_visibility(float depth) {
- float vis = 1.0;
- # if POISSON_DISK_NUM != NO_SOFT_SHADOWS
- vec4 pcf_blur_radii = u_pcf_blur_radii;
- # else
- vec4 pcf_blur_radii = vec4(0.0);
- # endif
- // NOTE: possible division by zero
- vec3 shadow_coord0 = v_shadow_coord0.xyz / v_shadow_coord0.w;
- // fix for shadow maps from perspective camera (actually works for
- // all cameras): no shadows behind the camera
- if (v_shadow_coord0.w < 0.0)
- shadow_coord0.z = 0.0;
- # if CSM_SECTION1 || NUM_CAST_LAMPS > 1
- vec3 shadow_coord1 = v_shadow_coord1.xyz / v_shadow_coord1.w;
- if (v_shadow_coord1.w < 0.0)
- shadow_coord1.z = 0.0;
- # endif
- # if CSM_SECTION2 || NUM_CAST_LAMPS > 2
- vec3 shadow_coord2 = v_shadow_coord2.xyz / v_shadow_coord2.w;
- if (v_shadow_coord2.w < 0.0)
- shadow_coord2.z = 0.0;
- # endif
- # if CSM_SECTION3 || NUM_CAST_LAMPS > 3
- vec3 shadow_coord3 = v_shadow_coord3.xyz / v_shadow_coord3.w;
- if (v_shadow_coord3.w < 0.0)
- shadow_coord3.z = 0.0;
- # endif
- # if CSM_SECTION1
- if (is_tex_coords_inside(shadow_coord0.xy, 0.0)) {
- vis = get_visibility_blended(shadow_coord0, shadow_coord1,
- u_shadow_map0, u_shadow_map1, pcf_blur_radii[0],
- pcf_blur_radii[1], u_csm_center_dists[0], depth);
- }
- # else
- // NOTE: small indent for single cascade blur (especially for non-csm scheme)
- if (is_tex_coords_inside(shadow_coord0.xy, FIRST_CASCADE_BLUR_INDENT)) {
- vis = get_visibility_faded(shadow_coord0, u_shadow_map0,
- pcf_blur_radii[0], u_csm_center_dists[0], depth);
- }
- # endif
- # if CSM_SECTION1
- else {
- if (is_tex_coords_inside(shadow_coord1.xy, 0.0)) {
- # if CSM_SECTION2
- vis = get_visibility_blended(shadow_coord1, shadow_coord2,
- u_shadow_map1, u_shadow_map2, pcf_blur_radii[1],
- pcf_blur_radii[2], u_csm_center_dists[1], depth);
- # else
- vis = get_visibility_faded(shadow_coord1, u_shadow_map1,
- pcf_blur_radii[1], u_csm_center_dists[1], depth);
- # endif
- }
- # if CSM_SECTION2
- else {
- if (is_tex_coords_inside(shadow_coord2.xy, 0.0)) {
- # if CSM_SECTION3
- vis = get_visibility_blended(shadow_coord2, shadow_coord3,
- u_shadow_map2, u_shadow_map3, pcf_blur_radii[2],
- pcf_blur_radii[3], u_csm_center_dists[2], depth);
- # else
- vis = get_visibility_faded(shadow_coord2, u_shadow_map2,
- pcf_blur_radii[2], u_csm_center_dists[2], depth);
- # endif
- }
- # if CSM_SECTION3
- else {
- if (is_tex_coords_inside(shadow_coord3.xy, 0.0))
- vis = get_visibility_faded(shadow_coord3, u_shadow_map3,
- pcf_blur_radii[3], u_csm_center_dists[3], depth);
- }
- # endif // CSM_SECTION3
- }
- # endif // CSM_SECTION2
- }
- # endif // CSM_SECTION1
- # if NUM_CAST_LAMPS > 1
- float vis_lamp_1 = shadow_map_visibility(shadow_coord1, u_shadow_map1, pcf_blur_radii[0]);
- # else
- float vis_lamp_1 = 0.0;
- # endif
- # if NUM_CAST_LAMPS > 2
- float vis_lamp_2 = shadow_map_visibility(shadow_coord2, u_shadow_map2, pcf_blur_radii[0]);
- # else
- float vis_lamp_2 = 0.0;
- # endif
- # if NUM_CAST_LAMPS > 3
- float vis_lamp_3 = shadow_map_visibility(shadow_coord3, u_shadow_map3, pcf_blur_radii[0]);
- # else
- float vis_lamp_3 = 1.0;
- # endif
- return vec4(vis, vis_lamp_1, vis_lamp_2, vis_lamp_3);
- }
- #endif // SHADOW_USAGE == SHADOW_MASK_GENERATION || SHADOW_USAGE == SHADOW_MAPPING_BLEND
- vec4 calc_shadow_factor(inout vec3 D) {
- #if SHADOW_USAGE == SHADOW_MAPPING_OPAQUE
- // TODO:
- vec4 visibility = GLSL_TEXTURE(u_shadow_mask, v_tex_pos_clip.xy / v_tex_pos_clip.z);
- # if NUM_CAST_LAMPS < 3
- D *= visibility.a;
- # endif
- return visibility;
- #elif SHADOW_USAGE == SHADOW_MASK_GENERATION || SHADOW_USAGE == SHADOW_MAPPING_BLEND
- vec4 visibility = shadow_visibility(v_pos_view.z);
- return visibility;
- #else
- return vec4(1.0);
- #endif
- }
- #endif
|