Fix collisions. Switch to No-Culling Shadow Maps. Introduce Better Shadow Bias Calculation. Calculate Normals in the Shader.

main
andrewjhaman 1 year ago
parent fab5c86841
commit 3540468ef6

@ -3974,6 +3974,21 @@ void dbg3dline(Vec3 from, Vec3 to)
dbgline(from_screenspace, to_screenspace);
}
void dbg3dline2d(Vec2 a, Vec2 b) {
Vec3 a_3 = V3(a.x, 0.0, a.y);
Vec3 b_3 = V3(b.x, 0.0, b.y);
dbg3dline(a_3, b_3);
}
void dbg3dline2dOffset(Vec2 a, Vec2 offset) {
Vec3 a_3 = V3(a.x, 0.0, a.y);
Vec3 b_3 = V3(offset.x, 0.0, offset.y);
dbg3dline(a_3, AddV3(a_3,b_3));
}
void colorquadplane(Quad q, Color col)
{
Quad warped = {0};
@ -4223,6 +4238,41 @@ typedef struct MoveSlideParams
} MoveSlideParams;
Vec2 get_penetration_vector(AABB stable, AABB dynamic)
{
//Assumes we already know that they are colliding.
//It could be faster to use this info for collision detection as well,
//but this would require an intrusive refactor, and it is not the common
//case that things are colliding anyway, so it's actually not that much
//duplicated work.
Vec2 dynamic_centre = aabb_center(dynamic);
Vec2 dynamic_half_dims = MulV2F(aabb_size(dynamic), 0.5f);
stable.lower_right.x += dynamic_half_dims.x;
stable.lower_right.y -= dynamic_half_dims.y;
stable.upper_left.x -= dynamic_half_dims.x;
stable.upper_left.y += dynamic_half_dims.y;
float right_delta = stable.lower_right.x - dynamic_centre.x;
float left_delta = stable.upper_left.x - dynamic_centre.x;
float bottom_delta = stable.lower_right.y - dynamic_centre.y;
float top_delta = stable.upper_left.y - dynamic_centre.y;
float r = fabsf( right_delta);
float l = fabsf( left_delta);
float b = fabsf(bottom_delta);
float t = fabsf( top_delta);
if (r <= l && r <= b && r <= t)
return V2(right_delta, 0.0);
if (left_delta <= r && l <= b && l <= t)
return V2(left_delta, 0.0);
if (b <= r && b <= l && b <= t)
return V2(0.0, bottom_delta);
return V2(0.0, top_delta);
}
// returns new pos after moving and sliding against collidable things
Vec2 move_and_slide(MoveSlideParams p)
{
@ -4328,43 +4378,12 @@ Vec2 move_and_slide(MoveSlideParams p)
BUFF_ITER(CollisionObj, &overlapping_smallest_first)
{
AABB to_depenetrate_from = it->aabb;
int iters_tried_to_push_apart = 0;
bool happened_with_this_one = false;
while (overlapping(to_depenetrate_from, at_new) && iters_tried_to_push_apart < 500)
{
happened_with_this_one = true;
const float move_dist = 0.01f;
info.happened = true;
Vec2 from_point = aabb_center(to_depenetrate_from);
Vec2 to_player = NormV2(SubV2(aabb_center(at_new), from_point));
Vec2 compass_dirs[4] = {
V2(1.0, 0.0),
V2(-1.0, 0.0),
V2(0.0, 1.0),
V2(0.0, -1.0),
};
int closest_index = -1;
float closest_dot = -99999999.0f;
for (int i = 0; i < 4; i++)
{
float dot = DotV2(compass_dirs[i], to_player);
if (dot > closest_dot)
{
closest_index = i;
closest_dot = dot;
}
}
// sometimes when objects are perfectly overlapping, every dot product is negative infinity
if(closest_index == -1) closest_index = 0;
Vec2 move_dir = compass_dirs[closest_index];
info.normal = move_dir;
dbgplanevec(from_point, MulV2F(move_dir, 30.0f));
Vec2 move = MulV2F(move_dir, move_dist);
at_new.upper_left = AddV2(at_new.upper_left, move);
at_new.lower_right = AddV2(at_new.lower_right, move);
iters_tried_to_push_apart++;
}
Vec2 resolution_vector = get_penetration_vector(to_depenetrate_from, at_new);
at_new.upper_left = AddV2(at_new.upper_left , resolution_vector);
at_new.lower_right = AddV2(at_new.lower_right, resolution_vector);
bool happened_with_this_one = true;
if(happened_with_this_one)
{
bool already_in_happened = false;
@ -4680,7 +4699,7 @@ void draw_dialog_panel(Entity *talking_to, float alpha)
line(AddV2(dialog_quad.lr, V2(line_width, 0.0)), AddV2(dialog_quad.ll, V2(-line_width, 0.0)), line_width, line_color);
line(dialog_quad.ll, dialog_quad.ul, line_width, line_color);
float padding = 5.0f;
float padding = 7.5f;
dialog_panel.upper_left = AddV2(dialog_panel.upper_left, V2(padding, -padding));
dialog_panel.lower_right = AddV2(dialog_panel.lower_right, V2(-padding, padding));
@ -4945,7 +4964,7 @@ Shadow_State init_shadow_state() {
},
.shader = sg_make_shader(shadow_mapper_program_shader_desc(sg_query_backend())),
// Cull front faces in the shadow map pass
.cull_mode = SG_CULLMODE_FRONT,
// .cull_mode = SG_CULLMODE_BACK,
.sample_count = 1,
.depth = {
.pixel_format = SG_PIXELFORMAT_DEPTH,
@ -5078,6 +5097,7 @@ Shadow_Volume_Params calculate_shadow_volume_params(Vec3 light_dir)
return result;
}
void frame(void)
{
static float speed_factor = 1.0f;

@ -7,7 +7,8 @@ in vec2 uv_in;
out vec3 pos;
out vec2 uv;
out vec4 light_space_fragment_position;
out vec3 light_dir;
out vec4 world_space_frag_pos;
uniform vs_params {
mat4 model;
@ -20,10 +21,13 @@ void main() {
pos = pos_in;
uv = uv_in;
vec4 world_space_frag_pos = model * vec4(pos_in, 1.0);
world_space_frag_pos = model * vec4(pos_in, 1.0);
vec4 frag_pos = view * world_space_frag_pos;
gl_Position = projection * frag_pos;
//@Speed I think we can just take the third row here and be fine.
light_dir = normalize(inverse(directional_light_space_matrix) * vec4(0.0, 0.0, -1.0, 0.0)).xyz;
light_space_fragment_position = directional_light_space_matrix * vec4(world_space_frag_pos.xyz, 1.0);
}
@end
@ -40,6 +44,8 @@ uniform fs_params {
in vec3 pos;
in vec2 uv;
in vec4 light_space_fragment_position;
in vec3 light_dir;
in vec4 world_space_frag_pos;
out vec4 frag_color;
@ -47,7 +53,7 @@ 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) {
float do_shadow_sample(sampler2D shadowMap, vec2 uv, float scene_depth, float n_dot_l) {
{
//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
@ -56,12 +62,21 @@ float do_shadow_sample(sampler2D shadowMap, vec2 uv, float scene_depth) {
return 1.0;
}
float map_depth = decodeDepth(texture(shadowMap, uv));
map_depth += 0.001;//bias to counter self-shadowing
// float bias = max(0.03f * (1.0f - n_dot_l), 0.005f);
// bias = clamp(bias, 0.0, 0.01);
float offset_scale_N = sqrt(1 - n_dot_l*n_dot_l);
float offset_scale_L = offset_scale_N / n_dot_l;
float bias = 0.0002 * offset_scale_N + 0.0001 * offset_scale_L;
map_depth += bias;
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) {
float bilinear_shadow_sample(sampler2D shadowMap, vec2 uv, int texture_width, int texture_height, float scene_depth_light_space, float n_dot_l) {
vec2 texture_dim = vec2(float(texture_width), float(texture_height));
vec2 texel_dim = vec2(1.0 / float(texture_width ), 1.0 / float(texture_height));
@ -75,10 +90,10 @@ float bilinear_shadow_sample(sampler2D shadowMap, vec2 uv, int texture_width, in
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);
float bl = do_shadow_sample(shadowMap, uv_0, scene_depth_light_space, n_dot_l);
float br = do_shadow_sample(shadowMap, uv_1, scene_depth_light_space, n_dot_l);
float tl = do_shadow_sample(shadowMap, uv_2, scene_depth_light_space, n_dot_l);
float tr = do_shadow_sample(shadowMap, uv_3, scene_depth_light_space, n_dot_l);
vec2 interp = fract(texel_uv);
@ -89,7 +104,7 @@ float bilinear_shadow_sample(sampler2D shadowMap, vec2 uv, int texture_width, in
return result;
}
float calculate_shadow_factor(sampler2D shadowMap, vec4 light_space_fragment_position) {
float calculate_shadow_factor(sampler2D shadowMap, vec4 light_space_fragment_position, float n_dot_l) {
float shadow = 1.0;
vec3 projected_coords = light_space_fragment_position.xyz / light_space_fragment_position.w;
@ -109,11 +124,13 @@ float calculate_shadow_factor(sampler2D shadowMap, vec4 light_space_fragment_pos
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 += bilinear_shadow_sample(shadowMap, shadow_uv+off, shadow_map_dimension, shadow_map_dimension, current_depth, n_dot_l);
}
}
shadow /= 25.0;
return shadow;
}
@ -126,12 +143,17 @@ void main() {
}
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;
vec3 normal = normalize(cross(dFdx(world_space_frag_pos.xyz), dFdy(world_space_frag_pos.xyz)));
float n_dot_l = clamp(dot(normal, light_dir), 0.0, 1.0);
float shadow_factor = calculate_shadow_factor(shadow_map, light_space_fragment_position, n_dot_l);
float lighting_factor = shadow_factor * n_dot_l;
lighting_factor = lighting_factor * 0.5 + 0.5;
frag_color = vec4(col.rgb*lighting_factor, 1.0);
frag_color = vec4(col.rgb*shadow_factor, 1.0);
}
}
@end

Loading…
Cancel
Save