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
This commit is contained in:
sergeypdev 2024-03-12 17:05:11 +04:00
parent 7600db3dca
commit a865ea4ab7
3 changed files with 34 additions and 5 deletions

View File

@ -24,7 +24,7 @@ pub const CSM_SPLITS = 4;
// 0 - uniform // 0 - uniform
// 1 - exponential // 1 - exponential
// 0.5 - mix between the two // 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(); pub const Render = @This();
@ -553,7 +553,23 @@ pub fn finish(self: *Render) void {
dir_aabb_min = pos.min(dir_aabb_min); dir_aabb_min = pos.min(dir_aabb_min);
dir_aabb_max = pos.max(dir_aabb_max); 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.* = .{ camera_matrix.* = .{

View File

@ -188,9 +188,9 @@ export fn game_init(global_allocator: *std.mem.Allocator) void {
_ = globals.g_mem.world.addEntity(.{ _ = globals.g_mem.world.addEntity(.{
.flags = .{ .dir_light = true, .rotate = true }, .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) }, .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(.{ // const light_root = globals.g_mem.world.addEntity(.{
@ -345,7 +345,7 @@ export fn game_update() bool {
c.SDL_SCANCODE_F7 => { c.SDL_SCANCODE_F7 => {
if (event.type == c.SDL_KEYDOWN) { if (event.type == c.SDL_KEYDOWN) {
if (gmem.render.camera.far == 10) { if (gmem.render.camera.far == 10) {
gmem.render.camera.far = 100; gmem.render.camera.far = 50;
} else { } else {
gmem.render.camera.far = 10; gmem.render.camera.far = 10;
} }

View File

@ -98,6 +98,19 @@ pub const AABB = struct {
return AABB.fromMinMax(min, max); 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 { pub const Frustum = struct {