v4k-git-backup/engine/art/shaderlib/shadowmap.glsl

237 lines
9.5 KiB
Plaintext
Raw Permalink Normal View History

2024-08-30 14:01:46 +00:00
#ifndef SHADOWMAP_GLSL
#define SHADOWMAP_GLSL
2024-08-30 10:19:50 +00:00
#include "utils.glsl"
2024-08-29 15:32:34 +00:00
uniform bool u_shadow_receiver;
2024-08-30 12:25:47 +00:00
uniform float u_cascade_distances[MAX_LIGHTS * NUM_SHADOW_CASCADES];
2024-08-29 15:32:34 +00:00
uniform samplerCube shadowMap[MAX_LIGHTS];
2024-08-30 01:46:46 +00:00
uniform sampler2D shadowMap2D[MAX_LIGHTS * NUM_SHADOW_CASCADES];
2024-09-02 11:10:35 +00:00
uniform sampler3D shadow_offsets;
uniform int shadow_filter_size;
uniform int shadow_window_size;
2024-08-24 17:32:25 +00:00
2024-08-30 21:23:07 +00:00
// const float bias_modifier[NUM_SHADOW_CASCADES] = float[NUM_SHADOW_CASCADES](0.95, 0.35, 0.20, 0.1, 0.1, 0.1);
2024-09-02 11:10:35 +00:00
const float bias_modifier[NUM_SHADOW_CASCADES] = float[NUM_SHADOW_CASCADES](1.0, 6.0, 9.0, 16.0);
// const float bias_modifier[NUM_SHADOW_CASCADES] = float[NUM_SHADOW_CASCADES](0.95, 0.35, 0.20, 0.15);
2024-08-30 10:19:50 +00:00
2024-09-02 17:48:15 +00:00
vec2 shadow_vsm_variance(vec3 dir, int light_index, float distance, float min_variance, float variance_transition, out float alpha) {
2024-09-02 13:45:52 +00:00
// Calculate the variance
2024-09-02 17:48:15 +00:00
vec3 sampledValue = texture(shadowMap[light_index], dir).rgb;
vec2 moments = sampledValue.rg;
alpha = 1.0;//sampledValue.b;
2024-09-02 13:45:52 +00:00
float variance = max(moments.y - (moments.x * moments.x), min_variance);
float d = distance - moments.x;
2024-09-02 17:48:15 +00:00
return (vec2(linstep(variance_transition, 1.0, variance / (variance + d * d)), moments.x));
2024-09-02 13:45:52 +00:00
}
2024-09-02 15:00:31 +00:00
float shadow_vsm(float distance, vec3 dir, int light_index, float min_variance, float variance_transition, float shadow_softness_raw, float penumbra_size) {
float clamped_distance = clamp(distance, 0.0, 200.0);
2024-09-02 13:45:52 +00:00
float shadow_softness = shadow_softness_raw * 10.0;
2024-09-02 15:00:31 +00:00
shadow_softness = mix(shadow_softness, distance * 10.0, penumbra_size);
distance = distance / 200;
2024-09-02 13:45:52 +00:00
// Get the offset coordinates
ivec3 ofs_coord = ivec3(0);
vec2 ofs = mod(gl_FragCoord.xy, vec2(shadow_window_size));
ofs_coord.yz = ivec2(ofs);
float ofs_sum = 0.0;
int samples_div2 = int(shadow_filter_size * shadow_filter_size / 2.0);
vec4 sc = vec4(dir, 1.0);
sc.z = dir.z;
2024-09-02 11:10:35 +00:00
2024-09-02 13:58:13 +00:00
vec2 tex_size = textureSize(shadowMap[light_index], 0);
vec3 texelSize = 1.0 / vec3(tex_size.xyy);
vec3 light_plane_normal = normalize(dir);
2024-09-02 14:00:21 +00:00
vec3 up_axis = normalize(view[1].xyz);
vec3 tangent = normalize(cross(light_plane_normal, up_axis));
2024-09-02 13:58:13 +00:00
vec3 bitangent = cross(light_plane_normal, tangent);
2024-08-30 19:00:04 +00:00
2024-09-02 13:45:52 +00:00
for (int i = 0; i < 4; i++) {
ofs_coord.x = i;
vec4 offsets = texelFetch(shadow_offsets, ofs_coord, 0) * shadow_softness;
2024-09-02 13:58:13 +00:00
vec3 offset_dir = tangent * offsets.r + bitangent * offsets.g;
sc.xyz = dir.xyz + offset_dir * texelSize;
2024-09-02 17:48:15 +00:00
float alpha;
vec2 variance = shadow_vsm_variance(sc.xyz, light_index, distance, min_variance, variance_transition, alpha);
ofs_sum += min(max(step(distance*alpha, variance.y), variance.x), 1.0);
2024-09-02 13:45:52 +00:00
2024-09-02 13:58:13 +00:00
offset_dir = tangent * offsets.b + bitangent * offsets.a;
sc.xyz = dir.xyz + offset_dir * texelSize;
2024-09-02 17:48:15 +00:00
variance = shadow_vsm_variance(sc.xyz, light_index, distance, min_variance, variance_transition, alpha);
ofs_sum += min(max(step(distance*alpha, variance.y), variance.x), 1.0);
2024-09-02 13:45:52 +00:00
}
float shadow_sum = ofs_sum / 8.0;
if (shadow_sum != 0.0 && shadow_sum != 1.0) {
for (int i = 4; i < samples_div2; i++) {
ofs_coord.x = i;
vec4 offsets = texelFetch(shadow_offsets, ofs_coord, 0) * shadow_softness;
2024-09-02 13:58:13 +00:00
vec3 offset_dir = tangent * offsets.r + bitangent * offsets.g;
sc.xyz = dir.xyz + offset_dir * texelSize;
2024-09-02 17:48:15 +00:00
float alpha;
vec2 variance = shadow_vsm_variance(sc.xyz, light_index, distance, min_variance, variance_transition, alpha);
ofs_sum += min(max(step(distance*alpha, variance.y), variance.x), 1.0);
2024-09-02 13:45:52 +00:00
2024-09-02 13:58:13 +00:00
offset_dir = tangent * offsets.b + bitangent * offsets.a;
sc.xyz = dir.xyz + offset_dir * texelSize;
2024-09-02 17:48:15 +00:00
variance = shadow_vsm_variance(sc.xyz, light_index, distance, min_variance, variance_transition, alpha);
ofs_sum += min(max(step(distance*alpha, variance.y), variance.x), 1.0);
2024-08-30 19:00:04 +00:00
}
2024-09-02 13:45:52 +00:00
shadow_sum = ofs_sum / (samples_div2 * 2.0);
2024-08-30 19:00:04 +00:00
}
2024-09-02 13:45:52 +00:00
// vec3 sampleDir = dir + (rand(vec2(v_position_ws.x, v_position_ws.y))*0.25f);
// float shadow = 0.0;
// vec2 moments = ;
// // Calculate the variance
// float variance = max(moments.y - (moments.x * moments.x), min_variance);
// float d = distance - moments.x;
// float p_max = linstep(variance_transition, 1.0, variance / (variance + d * d));
return shadow_sum;//min(max(step(distance, moments.x), shadow_sum), 1.0);
}
2024-09-02 17:48:15 +00:00
float shadowmap_cascade_sample(vec2 sc, int cascade_index, float blend_factor, out float alpha) {
vec2 s1 = texture(shadowMap2D[cascade_index], sc).rg;
2024-09-02 13:45:52 +00:00
// float s2 = texture(shadowMap2D[cascade_index + 1], sc).r;
// return mix(s1, s2, blend_factor);
2024-09-02 17:48:15 +00:00
alpha = 1.0;//s1.g;
return s1.r;
2024-08-29 15:32:34 +00:00
}
2024-09-02 13:45:52 +00:00
float shadow_csm(float distance, vec3 lightDir, int light_index, float shadow_bias, float normal_bias, float shadow_softness) {
2024-08-30 01:46:46 +00:00
// Determine which cascade to use
int cascade_index = -1;
2024-08-30 12:25:47 +00:00
int min_cascades_range = light_index * NUM_SHADOW_CASCADES;
int max_cascades_range = min_cascades_range + NUM_SHADOW_CASCADES;
for (int i = min_cascades_range; i < max_cascades_range; i++) {
2024-08-30 01:46:46 +00:00
if (distance < u_cascade_distances[i]) {
cascade_index = i;
break;
}
}
if (cascade_index == -1) {
2024-08-30 12:25:47 +00:00
cascade_index = max_cascades_range - 1;
2024-08-30 01:46:46 +00:00
}
2024-09-02 13:45:52 +00:00
int matrix_index = cascade_index - min_cascades_range;
// Blend cascades using a blend region value
float blend_region = 200.0;
float blend_factor = 0.0;
if (matrix_index < NUM_SHADOW_CASCADES - 1) {
blend_factor = 0.5;
}
// float cascade_start = u_cascade_distances[cascade_index];
// float cascade_end = u_cascade_distances[cascade_index + 1];
// float blend_start = cascade_end - blend_region;
// if (distance > blend_start) {
// blend_factor = smoothstep(blend_start, cascade_end, distance);
// }
// }
2024-08-30 01:46:46 +00:00
2024-08-30 14:01:46 +00:00
light_t light = u_lights[light_index];
2024-08-30 12:25:47 +00:00
2024-08-30 14:01:46 +00:00
vec4 fragPosLightSpace = light.shadow_matrix[matrix_index] * vec4(v_position_ws, 1.0);
2024-08-30 01:46:46 +00:00
2024-08-29 18:46:30 +00:00
// Perform perspective divide
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
// Transform to [0,1] range
projCoords = projCoords * 0.5 + 0.5;
2024-09-02 11:10:35 +00:00
vec4 sc = vec4(projCoords, 1.0);
2024-08-30 01:46:46 +00:00
2024-08-29 18:46:30 +00:00
float currentDepth = projCoords.z;
2024-08-30 01:46:46 +00:00
if (currentDepth > 1.0) {
return 1.0;
}
// Calculate bias
2024-08-29 18:46:30 +00:00
vec3 normal = normalize(vneye.xyz);
2024-09-02 11:10:35 +00:00
float bias = max(normal_bias * bias_modifier[matrix_index] * (1.0 - dot(normal, lightDir)), shadow_bias);
bias *= 1 / (u_cascade_distances[cascade_index]);
2024-08-30 10:19:50 +00:00
2024-08-30 19:00:04 +00:00
// CSM
2024-08-29 18:46:30 +00:00
float shadow = 0.0;
2024-08-30 12:25:47 +00:00
vec2 texelSize = 1.0 / textureSize(shadowMap2D[cascade_index], 0);
2024-08-30 10:19:50 +00:00
2024-09-02 11:10:35 +00:00
// Get the offset coordinates
ivec3 ofs_coord = ivec3(0);
vec2 ofs = mod(gl_FragCoord.xy, vec2(shadow_window_size));
ofs_coord.yz = ivec2(ofs);
float ofs_sum = 0.0;
int samples_div2 = int(shadow_filter_size * shadow_filter_size / 2.0);
for (int i = 0; i < 4; i++) {
ofs_coord.x = i;
2024-09-02 13:45:52 +00:00
vec4 offsets = texelFetch(shadow_offsets, ofs_coord, 0) * shadow_softness;
2024-09-02 11:10:35 +00:00
sc.xy = projCoords.xy + offsets.rg * texelSize;
2024-09-02 17:48:15 +00:00
float alpha;
float csmDepth = shadowmap_cascade_sample(sc.xy, cascade_index, blend_factor, alpha);
ofs_sum += currentDepth - bias > csmDepth ? alpha : 0.0;
2024-09-02 11:10:35 +00:00
sc.xy = projCoords.xy + offsets.ba * texelSize;
2024-09-02 17:48:15 +00:00
csmDepth = shadowmap_cascade_sample(sc.xy, cascade_index, blend_factor, alpha);
ofs_sum += currentDepth - bias > csmDepth ? alpha : 0.0;
2024-08-29 18:46:30 +00:00
}
2024-09-02 11:10:35 +00:00
float shadow_sum = ofs_sum / 8.0;
if (shadow_sum != 0.0 && shadow_sum != 1.0) {
for (int i = 4; i < samples_div2; i++) {
ofs_coord.x = i;
2024-09-02 13:45:52 +00:00
vec4 offsets = texelFetch(shadow_offsets, ofs_coord, 0) * shadow_softness;
2024-09-02 11:10:35 +00:00
sc.xy = projCoords.xy + offsets.rg * texelSize;
2024-09-02 17:48:15 +00:00
float alpha;
float csmDepth = shadowmap_cascade_sample(sc.xy, cascade_index, blend_factor, alpha);
ofs_sum += currentDepth - bias > csmDepth ? alpha : 0.0;
2024-09-02 11:10:35 +00:00
sc.xy = projCoords.xy + offsets.ba * texelSize;
2024-09-02 17:48:15 +00:00
csmDepth = shadowmap_cascade_sample(sc.xy, cascade_index, blend_factor, alpha);
ofs_sum += currentDepth - bias > csmDepth ? alpha : 0.0;
2024-09-02 11:10:35 +00:00
}
shadow_sum = ofs_sum / (samples_div2 * 2.0);
2024-08-30 10:19:50 +00:00
}
2024-09-02 11:10:35 +00:00
return 1.0 - shadow_sum;
2024-08-29 18:46:30 +00:00
}
2024-08-30 14:01:46 +00:00
vec4 shadowmap(int idx, in vec4 peye, in vec4 neye) {
2024-08-29 15:32:34 +00:00
vec3 fragment = vec3(peye);
2024-08-30 12:25:47 +00:00
float shadowFactor = 1.0;
2024-08-30 14:01:46 +00:00
light_t light = u_lights[idx];
if (light.processed_shadows) {
if (light.type == LIGHT_DIRECTIONAL) {
2024-09-02 13:45:52 +00:00
shadowFactor = shadow_csm(-peye.z, light.dir, idx, light.shadow_bias, light.normal_bias, light.shadow_softness);
2024-08-30 14:01:46 +00:00
} else if (light.type == LIGHT_POINT || light.type == LIGHT_SPOT) {
vec3 light_pos = (view * vec4(light.pos, 1.0)).xyz;
vec3 dir = light_pos - fragment;
vec4 sc = inv_view * vec4(dir, 0.0);
2024-09-02 15:00:31 +00:00
shadowFactor = shadow_vsm(length(dir), -sc.xyz, idx, light.min_variance, light.variance_transition, light.shadow_softness, light.penumbra_size);
2024-08-24 17:32:25 +00:00
}
2024-08-29 15:32:34 +00:00
}
return vec4(vec3(shadowFactor), 1.0);
}
2024-08-30 14:01:46 +00:00
vec4 shadowing(int idx) {
2024-08-29 15:32:34 +00:00
if (u_shadow_receiver) {
2024-08-30 14:01:46 +00:00
return shadowmap(idx, vpeye, vneye);
2024-08-29 15:32:34 +00:00
} else {
return vec4(1.0);
}
}
2024-08-30 14:01:46 +00:00
#endif