Merge pull request #3 from andrewjhaman/main

Fit Shadows to Frustum
main
Cameron Murphy Reikes 12 months ago committed by GitHub
commit 02d3d30938
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

153
main.c

@ -4996,7 +4996,45 @@ float round_to_nearest(float input, float round_target)
return result;
}
Shadow_Volume_Params calculate_shadow_volume_params(Vec3 light_dir)
typedef struct
{
//For now we consider all vertices on the near plane to be equal to the camera position, and store that at vertices[0];
Vec3 vertices[5];
} FrustumVertices;
FrustumVertices get_frustum_vertices(Vec3 cam_pos, Vec3 cam_forward, Vec3 cam_right) {
FrustumVertices result = {0};
float aspect_ratio = (float)sapp_width() / (float)sapp_height();
const int num_frustum_vertices = sizeof(result.vertices)/sizeof(result.vertices[0]);
const float cascade_distance = FAR_PLANE_DISTANCE;
Vec2 far_plane_half_dims;
far_plane_half_dims.y = cascade_distance * tanf(FIELD_OF_VIEW * 0.5f);
far_plane_half_dims.x = far_plane_half_dims.y * aspect_ratio;
Vec3 cam_up = Cross(cam_right, cam_forward);
Vec3 far_plane_centre = AddV3(cam_pos, MulV3F(cam_forward, cascade_distance));
Vec3 far_plane_offset_to_right_side = MulV3F(cam_right, far_plane_half_dims.x);
Vec3 far_plane_offset_to_top_side = MulV3F(cam_up , far_plane_half_dims.y);
Vec3 far_plane_offset_to_left_side = MulV3F(far_plane_offset_to_right_side, -1.0);
Vec3 far_plane_offset_to_bot_side = MulV3F(far_plane_offset_to_top_side , -1.0);
result.vertices[0] = cam_pos;
result.vertices[1] = AddV3(far_plane_centre, AddV3(far_plane_offset_to_bot_side, far_plane_offset_to_left_side ));
result.vertices[2] = AddV3(far_plane_centre, AddV3(far_plane_offset_to_bot_side, far_plane_offset_to_right_side));
result.vertices[3] = AddV3(far_plane_centre, AddV3(far_plane_offset_to_top_side, far_plane_offset_to_right_side));
result.vertices[4] = AddV3(far_plane_centre, AddV3(far_plane_offset_to_top_side, far_plane_offset_to_left_side ));
return result;
}
Shadow_Volume_Params calculate_shadow_volume_params(Vec3 light_dir, Vec3 cam_pos, Vec3 cam_forward, Vec3 cam_right)
{
Shadow_Volume_Params result = {0};
@ -5009,55 +5047,34 @@ Shadow_Volume_Params calculate_shadow_volume_params(Vec3 light_dir)
//To make up for this, we add an extra padding-skirt to the bounds.
Mat4 light_space_matrix = LookAt_RH((Vec3){0}, light_dir, V3(0, 1, 0));
Vec3 scene_min = V3( INFINITY, INFINITY, INFINITY);
Vec3 scene_max = V3(-INFINITY, -INFINITY, -INFINITY);
Vec3 frustum_min = V3( INFINITY, INFINITY, INFINITY);
Vec3 frustum_max = V3(-INFINITY, -INFINITY, -INFINITY);
for(PlacedMesh *cur = level_threedee.placed_mesh_list; cur; cur = cur->next)
{
Vec3 p = MulM4V3(light_space_matrix, cur->t.offset);
FrustumVertices frustum_vertices_worldspace = get_frustum_vertices(cam_pos, cam_forward, cam_right);
const int num_frustum_vertices = sizeof(frustum_vertices_worldspace.vertices)/sizeof(frustum_vertices_worldspace.vertices[0]);
scene_min.x = fminf(scene_min.x, p.x);
scene_max.x = fmaxf(scene_max.x, p.x);
for (int i = 0; i < num_frustum_vertices; ++i) {
Vec3 p = frustum_vertices_worldspace.vertices[i];
scene_min.y = fminf(scene_min.y, p.y);
scene_max.y = fmaxf(scene_max.y, p.y);
scene_min.z = fminf(scene_min.z, p.z);
scene_max.z = fmaxf(scene_max.z, p.z);
}
p = MulM4V3(light_space_matrix, p);
ENTITIES_ITER(gs.entities)
{
if(it->is_npc || it->is_character)
{
Transform draw_with = entity_transform(it);
Vec3 p = MulM4V3(light_space_matrix, draw_with.offset);
frustum_min.x = fminf(frustum_min.x, p.x);
frustum_max.x = fmaxf(frustum_max.x, p.x);
scene_min.x = fminf(scene_min.x, p.x);
scene_max.x = fmaxf(scene_max.x, p.x);
scene_min.y = fminf(scene_min.y, p.y);
scene_max.y = fmaxf(scene_max.y, p.y);
scene_min.z = fminf(scene_min.z, p.z);
scene_max.z = fmaxf(scene_max.z, p.z);
}
frustum_min.y = fminf(frustum_min.y, p.y);
frustum_max.y = fmaxf(frustum_max.y, p.y);
frustum_min.z = fminf(frustum_min.z, p.z);
frustum_max.z = fmaxf(frustum_max.z, p.z);
}
//pad to account for entity width
float pad = 2.5f;
scene_min.x -= pad;
scene_min.y -= pad;
scene_max.x += pad;
scene_max.y += pad;
result.l = scene_min.x;
result.r = scene_max.x;
result.l = frustum_min.x;
result.r = frustum_max.x;
result.b = scene_min.y;
result.t = scene_max.y;
result.b = frustum_min.y;
result.t = frustum_max.y;
float w = result.r - result.l;
float h = result.t - result.b;
@ -5094,6 +5111,54 @@ Shadow_Volume_Params calculate_shadow_volume_params(Vec3 light_dir)
return result;
}
void debug_draw_img(sg_image img, int index) {
draw_quad((DrawParams){quad_at(V2(512.0f*index, 512.0), V2(512.0, 512.0)), IMG(state.shadows.color_img), WHITE, .layer=LAYER_UI});
}
void debug_draw_img_with_border(sg_image img, int index) {
float bs = 50.0;
draw_quad((DrawParams){quad_at(V2(512.0f*index, 512.0), V2(512.0, 512.0)), state.shadows.color_img, (AABB){V2(-bs, -bs), AddV2(img_size(img), V2(bs, bs))}, WHITE, .layer=LAYER_UI});
}
void debug_draw_shadow_info(Vec3 frustum_tip, Vec3 cam_forward, Vec3 cam_right, Mat4 light_space_matrix) {
debug_draw_img(state.shadows.color_img, 0);
FrustumVertices fv = get_frustum_vertices(frustum_tip, cam_forward, cam_right);
Vec2 projs[5];
for (int i = 0; i < 5; ++i) {
Vec3 v = fv.vertices[i];
Vec4 p = V4(v.x, v.y, v.z, 1.0);
Vec4 proj = MulM4V4(light_space_matrix, p);
proj.x /= proj.w;
proj.y /= proj.w;
proj.z /= proj.w;
proj.x *= 0.5f;
proj.x += 0.5f;
proj.y *= 0.5f;
proj.y += 0.5f;
proj.z *= 0.5f;
proj.z += 0.5f;
proj.x *= 512.0f;
proj.y *= 512.0f;
projs[i] = proj.XY;
dbgsquare(proj.XY);
}
dbgline(projs[0], projs[1]);
dbgline(projs[0], projs[2]);
dbgline(projs[0], projs[3]);
dbgline(projs[0], projs[4]);
dbgline(projs[1], projs[2]);
dbgline(projs[2], projs[3]);
dbgline(projs[3], projs[4]);
dbgline(projs[4], projs[1]);
}
void actually_draw_thing(DrawnThing *it, Mat4 light_space_matrix, bool for_outline)
{
if(it->mesh)
@ -5170,7 +5235,7 @@ void actually_draw_thing(DrawnThing *it, Mat4 light_space_matrix, bool for_outli
// I moved this out into its own separate function so that you could
// define helper functions to be used multiple times in it, and those functions
// would be near the actual 3d drawing in the file
void flush_all_drawn_things(Vec3 light_dir)
void flush_all_drawn_things(Vec3 light_dir, Vec3 cam_pos, Vec3 cam_facing, Vec3 cam_right)
{
// Draw all the 3D drawn things. Draw the shadows, then draw the things with the shadows.
// Process armatures and upload their skeleton textures
@ -5254,10 +5319,12 @@ void flush_all_drawn_things(Vec3 light_dir)
// do the shadow pass
Mat4 light_space_matrix;
{
Shadow_Volume_Params svp = calculate_shadow_volume_params(light_dir);
Shadow_Volume_Params svp = calculate_shadow_volume_params(light_dir, cam_pos, cam_facing, cam_right);
Mat4 shadow_view = LookAt_RH(V3(0, 0, 0), light_dir, V3(0, 1, 0));
Mat4 shadow_projection = Orthographic_RH_NO(svp.l, svp.r, svp.b, svp.t, svp.n, svp.f);
light_space_matrix = MulM4(shadow_projection, shadow_view);
// debug_draw_shadow_info(cam_pos, cam_facing, cam_right, light_space_matrix);
sg_begin_pass(state.shadows.pass, &state.shadows.pass_action);
@ -5552,7 +5619,7 @@ void frame(void)
}
flush_all_drawn_things(light_dir);
flush_all_drawn_things(light_dir, cam_pos, facing, right);
// draw the freaking outline. Play ball!
draw_quad((DrawParams){quad_at(V2(0.0, screen_size().y), screen_size()), IMG(state.outline_pass_image), WHITE, .layer = LAYER_UI_FG, .custom_pipeline = state.twodee_outline_pip});

@ -147,7 +147,7 @@ float do_shadow_sample(sampler2D shadowMap, vec2 uv, float scene_depth, float n_
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;
float bias = 0.0004 * offset_scale_N + 0.0001 * offset_scale_L;
map_depth += bias;

@ -60,5 +60,5 @@
//Rendering
#define FIELD_OF_VIEW (PI32/4.0f)
#define NEAR_PLANE_DISTANCE (0.01f)
#define FAR_PLANE_DISTANCE (1000.0f)
#define FAR_PLANE_DISTANCE (45.0f)
#define SHADOW_MAP_DIMENSION (2048)

Loading…
Cancel
Save