You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
3.7 KiB
GLSL

@module threedee
@vs vs
in vec3 pos_in;
in vec2 uv_in;
out vec3 pos;
out vec2 uv;
out vec4 light_space_fragment_position;
uniform vs_params {
mat4 model;
mat4 view;
mat4 projection;
mat4 directional_light_space_matrix;
};
void main() {
pos = pos_in;
uv = uv_in;
vec4 world_space_frag_pos = model * vec4(pos_in, 1.0);
vec4 frag_pos = view * world_space_frag_pos;
gl_Position = projection * frag_pos;
light_space_fragment_position = directional_light_space_matrix * vec4(world_space_frag_pos.xyz, 1.0);
}
@end
@fs fs
uniform sampler2D tex;
uniform sampler2D shadow_map;
uniform fs_params {
int shadow_map_dimension;
};
in vec3 pos;
in vec2 uv;
in vec4 light_space_fragment_position;
out vec4 frag_color;
float decodeDepth(vec4 rgba) {
return dot(rgba, vec4(1.0, 1.0/255.0, 1.0/65025.0, 1.0/16581375.0));
}
float do_shadow_sample(sampler2D shadowMap, vec2 uv, float scene_depth) {
{
//WebGL does not support GL_CLAMP_TO_BORDER, or border colors at all it seems, so we have to check explicitly.
//This will probably slow down other versions which do support texture borders, but the current system does
// not provide a non-overly complex way to include/not-include this code based on the backend. So here it is.
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0)
return 1.0;
}
float map_depth = decodeDepth(texture(shadowMap, uv));
map_depth += 0.001;//bias to counter self-shadowing
return step(scene_depth, map_depth);
}
float bilinear_shadow_sample(sampler2D shadowMap, vec2 uv, int texture_width, int texture_height, float scene_depth_light_space) {
vec2 texture_dim = vec2(float(texture_width), float(texture_height));
vec2 texel_dim = vec2(1.0 / float(texture_width ), 1.0 / float(texture_height));
vec2 texel_uv = uv * vec2(texture_dim);
vec2 texel_uv_floor = floor(texel_uv) * texel_dim;
vec2 texel_uv_ceil = ceil(texel_uv) * texel_dim;
vec2 uv_0 = texel_uv_floor;
vec2 uv_1 = vec2(texel_uv_ceil.x , texel_uv_floor.y);
vec2 uv_2 = vec2(texel_uv_floor.x, texel_uv_ceil.y );
vec2 uv_3 = vec2(texel_uv_ceil.x , texel_uv_ceil.y );
float bl = do_shadow_sample(shadowMap, uv_0, scene_depth_light_space);
float br = do_shadow_sample(shadowMap, uv_1, scene_depth_light_space);
float tl = do_shadow_sample(shadowMap, uv_2, scene_depth_light_space);
float tr = do_shadow_sample(shadowMap, uv_3, scene_depth_light_space);
vec2 interp = fract(texel_uv);
float bot = mix(bl, br, interp.x);
float top = mix(tl, tr, interp.x);
float result = mix(bot, top, interp.y);
return result;
}
float calculate_shadow_factor(sampler2D shadowMap, vec4 light_space_fragment_position) {
float shadow = 1.0;
vec3 projected_coords = light_space_fragment_position.xyz / light_space_fragment_position.w;
if(projected_coords.z > 1.0)
return shadow;
projected_coords = projected_coords * 0.5f + 0.5f;
float current_depth = projected_coords.z;
vec2 shadow_uv = projected_coords.xy;
float texel_step_size = 1.0 / float(shadow_map_dimension);
for (int x=-2; x<=2; x++) {
for (int y=-2; y<=2; y++) {
vec2 off = vec2(x*texel_step_size, y*texel_step_size);
// shadow += do_shadow_sample(shadowMap, shadow_uv+off, current_depth);
shadow += bilinear_shadow_sample(shadowMap, shadow_uv+off, shadow_map_dimension, shadow_map_dimension, current_depth);
}
}
shadow /= 25.0;
return shadow;
}
void main() {
vec4 col = texture(tex, uv);
if(col.a < 0.5)
{
discard;
}
else
{
vec3 light_dir = normalize(vec3(1, -1, 0));
float shadow_factor = calculate_shadow_factor(shadow_map, light_space_fragment_position);
shadow_factor = shadow_factor * 0.5 + 0.5;
frag_color = vec4(col.rgb*shadow_factor, 1.0);
}
}
@end
@program program vs fs