diff --git a/editor/editor.jai b/editor/editor.jai index a5649c6..9f9fd5f 100644 --- a/editor/editor.jai +++ b/editor/editor.jai @@ -131,7 +131,7 @@ Editor :: struct { init_editor :: () { aspect_ratio := cast(float)engine.renderer.render_target_width / cast(float)engine.renderer.render_target_height; - engine.editor.camera = create_perspective_camera(.{0, 10, -10}, yaw=0, pitch=-40, roll=0.0, fov=40, aspect=aspect_ratio); + engine.editor.camera = create_perspective_camera(.{0, 10, -10}, yaw=0, pitch=-40, roll=0.0, fov=40, z_far=100.0, aspect=aspect_ratio); init_transform_gizmo(); diff --git a/module.jai b/module.jai index f9950bd..76c0ae7 100644 --- a/module.jai +++ b/module.jai @@ -41,6 +41,8 @@ Engine_Core :: struct { directional_light_buffer : Buffer_Handle; point_light_buffer : Buffer_Handle; + on_frustum_render: (Vector3, Vector3); + procs: struct { on_scene_loaded: (*Scene, Engine_Mode); on_pre_scene_loaded: (*Scene, Engine_Mode); diff --git a/renderer/engine_buffers.jai b/renderer/engine_buffers.jai index 2fe5b58..85c88c2 100644 --- a/renderer/engine_buffers.jai +++ b/renderer/engine_buffers.jai @@ -1,7 +1,7 @@ calc_tight_light_projection :: (camera: Camera, light_direction: Vector3) -> Matrix4 { // View space camera frustum aspect_ratio := cast(float)engine.renderer.render_target_height / cast(float)engine.renderer.render_target_width; - frustum := get_frustum(camera.fov, aspect_ratio, camera.z_near, camera.z_far); + frustum := get_frustum(camera.fov, aspect_ratio, camera.z_near-20.0, camera.z_far+20); // View frustum back to world space success :, inv_camera_view := inverse(camera.view_matrix); @@ -22,6 +22,9 @@ calc_tight_light_projection :: (camera: Camera, light_direction: Vector3) -> Mat light_space_frustum = transform(view_frustum_in_world_space, light_view); final_aabb := get_frustum_aabb(light_space_frustum); + // Padding + //final_aabb.min -= .{8,5,8}; + //final_aabb.max += .{20,0,20}; // Texel size calculation based on shadow map resolution (e.g., 2048x2048) texel_size_x := (final_aabb.max.x - final_aabb.min.x) / 4096.0; @@ -35,15 +38,76 @@ calc_tight_light_projection :: (camera: Camera, light_direction: Vector3) -> Mat final_aabb.max.x = final_aabb.min.x + (texel_size_x * 4096.0); final_aabb.max.y = final_aabb.min.y + (texel_size_y * 4096.0); - // Padding - final_aabb.min -= .{8,5,8}; - final_aabb.max += .{8,50, 8}; light_projection := orthographic_lh_projection_matrix(final_aabb.min.x, final_aabb.max.x, final_aabb.min.y, final_aabb.max.y, final_aabb.min.z, final_aabb.max.z); return light_projection * light_view; } +calculate_sun_transform :: (camera: Camera, light_direction: Vector3) -> Matrix4 { + success, inv_viewproj := inverse(camera.projection_matrix * camera.view_matrix); + + view : Matrix4; + proj : Matrix4; + + ndc : [8] Vector4 = .[ + .{-1, -1, 0, 1}, .{1, -1, 0, 1}, .{-1, 1, 0, 1}, .{1, 1, 0, 1}, // near plane + .{-1, -1, 1, 1}, .{1, -1, 1, 1}, .{-1, 1, 1, 1}, .{1, 1, 1, 1} // far plane + ]; + + corners : [8] Vector3; + center : Vector3; + + for i: 0..7 { + world := inv_viewproj * ndc[i]; + corners[i] = world.xyz / world.w; + center += corners[i]; + } + + center /= 8.0; + + { + // Build light basis + forward := normalize(-light_direction); + up := ifx abs(forward.y) > 0.99 then Vector3.{0, 0, 1} else .{0, 1, 0}; + right := normalize(cross(up, forward)); + up = cross(forward, right); + + // Build view matrix manually (row-major layout) + view = Matrix4_Identity; + view.v[0] = Vector4.{right.x, right.y, right.z, 0.0}; + view.v[1] = Vector4.{up.x, up.y, up.z, 0.0}; + view.v[2] = Vector4.{forward.x, forward.y, forward.z, 0.0}; + view.v[3] = Vector4.{-dot(right, center), + -dot(up, center), + -dot(forward, center), + 1.0}; + } + + { + min_bounds : Vector3 = .{FLOAT32_MAX, FLOAT32_MAX, FLOAT32_MAX}; + max_bounds : Vector3 = .{-FLOAT32_MAX, -FLOAT32_MAX, -FLOAT32_MAX}; + + for i: 0..7 { + ls := transform_position(corners[i], view); + min_bounds = min(min_bounds, ls); + max_bounds = max(max_bounds, ls); + } + + // Step 5: Build orthographic projection (DX11 Z: 0..1) + left := min_bounds.x; + right := max_bounds.x; + bottom := min_bounds.y; + top := max_bounds.y; + near_z := min_bounds.z; + far_z := max_bounds.z; + + proj = orthographic_lh_projection_matrix(left, right, bottom, top, near_z, far_z); + } + + return proj * view; +} + update_light_buffer :: () { scene := engine.current_scene; diff --git a/renderer/render_graph.jai b/renderer/render_graph.jai index 7e99e01..1b764d0 100644 --- a/renderer/render_graph.jai +++ b/renderer/render_graph.jai @@ -90,11 +90,12 @@ set_render_pass_clear_color :: (rp: Render_Pass_Handle, input_index: s32, color: execute_render_pass :: (render_pass: Render_Pass) { // @Incomplete: Add command buffer as parameter if render_pass.render_targets.count == 0 { if render_pass.has_depth_stencil { - push_cmd_set_render_targets(engine.renderer, depth_stencil_enabled=render_pass.has_depth_stencil, depth_stencil_buffer=render_pass.depth_stencil); - push_cmd_clear_depth_stencil(engine.renderer, render_pass.depth_stencil, 1.0); width := ifx render_pass.width == SWAPCHAIN_SIZE then engine.renderer.render_target_width else render_pass.width; height := ifx render_pass.height == SWAPCHAIN_SIZE then engine.renderer.render_target_height else render_pass.height; push_cmd_set_viewport(engine.renderer, width, height); + + push_cmd_set_render_targets(engine.renderer, depth_stencil_enabled=render_pass.has_depth_stencil, depth_stencil_buffer=render_pass.depth_stencil); + push_cmd_clear_depth_stencil(engine.renderer, render_pass.depth_stencil, 1.0); } else { assert(render_pass.uses_backbuffer); push_cmd_set_backbuffer(engine.renderer);