From a865ea4ab7294c104e5e9e41d13177714d006a51 Mon Sep 17 00:00:00 2001 From: sergeypdev Date: Tue, 12 Mar 2024 17:05:11 +0400 Subject: [PATCH] Use bounding sphere instead of AABB to calculate projection matrix for CSM split This reduces flickering somewhat because shadow map resolution doesn't change so much --- src/Render.zig | 20 ++++++++++++++++++-- src/game.zig | 6 +++--- src/math.zig | 13 +++++++++++++ 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/Render.zig b/src/Render.zig index d3aa644..e0bb57b 100644 --- a/src/Render.zig +++ b/src/Render.zig @@ -24,7 +24,7 @@ pub const CSM_SPLITS = 4; // 0 - uniform // 1 - exponential // 0.5 - mix between the two -pub const CSM_EXPO_UNIFORM_FACTOR = 0.9; +pub const CSM_EXPO_UNIFORM_FACTOR = 0.5; pub const Render = @This(); @@ -553,7 +553,23 @@ pub fn finish(self: *Render) void { dir_aabb_min = pos.min(dir_aabb_min); dir_aabb_max = pos.max(dir_aabb_max); } - projection = math.orthographic(dir_aabb_min.x(), dir_aabb_max.x(), dir_aabb_min.y(), dir_aabb_max.y(), -dir_aabb_max.z(), -dir_aabb_min.z()); + // Flip z because it's negative in view space, but near, far is positive + { + const min_z = dir_aabb_min.z(); + dir_aabb_min.zMut().* = -dir_aabb_max.z(); + dir_aabb_max.zMut().* = -min_z; + } + const b_sphere = math.AABB.fromMinMax(dir_aabb_min, dir_aabb_max).toSphere(); + + // NOTE: Use bounding sphere instead of AABB to prevent split size changing with rotation + projection = math.orthographic( + b_sphere.origin.x() - b_sphere.radius, + b_sphere.origin.x() + b_sphere.radius, + b_sphere.origin.y() - b_sphere.radius, + b_sphere.origin.y() + b_sphere.radius, + b_sphere.origin.z() - b_sphere.radius, + b_sphere.origin.z() + b_sphere.radius, + ); } camera_matrix.* = .{ diff --git a/src/game.zig b/src/game.zig index 340205e..4e115b3 100644 --- a/src/game.zig +++ b/src/game.zig @@ -188,9 +188,9 @@ export fn game_init(global_allocator: *std.mem.Allocator) void { _ = globals.g_mem.world.addEntity(.{ .flags = .{ .dir_light = true, .rotate = true }, - .transform = .{ .rot = Quat.fromEulerAngles(Vec3.new(89, 0, 0)) }, + .transform = .{ .rot = Quat.fromEulerAngles(Vec3.new(20, 0, 0)) }, .light = .{ .color_intensity = Vec4.new(1, 1, 0.83, 0.7) }, - .rotate = .{ .axis = Vec3.up(), .rate = -45 }, + .rotate = .{ .axis = Vec3.up(), .rate = -10 }, }); // const light_root = globals.g_mem.world.addEntity(.{ @@ -345,7 +345,7 @@ export fn game_update() bool { c.SDL_SCANCODE_F7 => { if (event.type == c.SDL_KEYDOWN) { if (gmem.render.camera.far == 10) { - gmem.render.camera.far = 100; + gmem.render.camera.far = 50; } else { gmem.render.camera.far = 10; } diff --git a/src/math.zig b/src/math.zig index 5aede3e..d7c9c9a 100644 --- a/src/math.zig +++ b/src/math.zig @@ -98,6 +98,19 @@ pub const AABB = struct { return AABB.fromMinMax(min, max); } + + pub fn toSphere(self: *const AABB) BoundingSphere { + const max_extent = @max(@max(self.extents.x(), self.extents.y()), self.extents.z()); + return BoundingSphere{ + .origin = self.origin, + .radius = max_extent, + }; + } +}; + +pub const BoundingSphere = struct { + origin: Vec3 = Vec3.zero(), + radius: f32 = 0, }; pub const Frustum = struct {