diff --git a/core/camera.jai b/core/camera.jai index 0284249..30b8ba3 100644 --- a/core/camera.jai +++ b/core/camera.jai @@ -35,7 +35,7 @@ Camera :: struct { dirty : bool; } -create_perspective_camera :: (position: Vector3 = .{}, fov: float, aspect: float, yaw: float = 0.0, pitch: float = 0.0, roll: float = 0.0, z_near: float = 0.1, z_far: float = 1000.0) -> Camera { +create_perspective_camera :: (position: Vector3 = .{}, fov: float, aspect: float, yaw: float = 0.0, pitch: float = 0.0, roll: float = 0.0, z_near: float = 0.1, z_far: float = 200.0) -> Camera { camera : Camera; camera.type = .PERSPECTIVE; camera.world_up = .{0,1,0}; @@ -89,7 +89,6 @@ orthographic_lh_projection_matrix :: (left: float, right: float, bottom: float, return m; } - make_lh_projection_matrix :: (fov_vertical: float, aspect_ratio_horizontal_over_vertical: float, z_near: float, z_far: float, x_offset:=0.0, y_offset:=0.0, depth_range_01:=false) -> Matrix4 { result := Matrix4_Identity; diff --git a/core/frustum.jai b/core/frustum.jai new file mode 100644 index 0000000..2f61263 --- /dev/null +++ b/core/frustum.jai @@ -0,0 +1,68 @@ +Frustum :: struct { + near_top_left: Vector3; + near_bottom_left: Vector3; + near_top_right: Vector3; + near_bottom_right: Vector3; + + far_top_left: Vector3; + far_bottom_left: Vector3; + far_top_right: Vector3; + far_bottom_right: Vector3; +} + +get_frustum :: (fov: float, aspect_ratio: float, z_near: float, z_far: float) -> Frustum { + frustum: Frustum = ---; + + tan_half_fov := tan(DEGREES_TO_RADIANS * fov * 0.5); + + near_z := z_near; + near_x := near_z * tan_half_fov; + near_y := near_z * tan_half_fov * aspect_ratio; + + frustum.near_top_left = .{-near_x, near_y, near_z}; + frustum.near_bottom_left = .{-near_x, -near_y, near_z}; + frustum.near_top_right = .{near_x, near_y, near_z}; + frustum.near_bottom_right = .{near_x, -near_y, near_z}; + + far_z := z_far; + far_x := far_z * tan_half_fov; + far_y := far_z * tan_half_fov * aspect_ratio; + + frustum.far_top_left = .{-far_x, far_y, far_z}; + frustum.far_bottom_left = .{-far_x, -far_y, far_z}; + frustum.far_top_right = .{far_x, far_y, far_z}; + frustum.far_bottom_right = .{far_x, -far_y, far_z}; + + return frustum; +} + +get_frustum_aabb :: (frustum: Frustum) -> AABB { + aabb: AABB; + aabb_add(*aabb, frustum.near_top_left); + aabb_add(*aabb, frustum.near_bottom_left); + aabb_add(*aabb, frustum.near_top_right); + aabb_add(*aabb, frustum.near_bottom_right); + + aabb_add(*aabb, frustum.far_top_left); + aabb_add(*aabb, frustum.far_bottom_left); + aabb_add(*aabb, frustum.far_top_right); + aabb_add(*aabb, frustum.far_bottom_right); + + return aabb; +} + +transform :: (frustum: Frustum, matrix: Matrix4) -> Frustum { + transformed_frustum: Frustum = ---; + + transformed_frustum.near_top_left = transform_position(frustum.near_top_left, matrix); + transformed_frustum.near_bottom_left = transform_position(frustum.near_bottom_left, matrix); + transformed_frustum.near_top_right = transform_position(frustum.near_top_right, matrix); + transformed_frustum.near_bottom_right = transform_position(frustum.near_bottom_right, matrix); + + transformed_frustum.far_top_left = transform_position(frustum.far_top_left, matrix); + transformed_frustum.far_bottom_left = transform_position(frustum.far_bottom_left, matrix); + transformed_frustum.far_top_right = transform_position(frustum.far_top_right, matrix); + transformed_frustum.far_bottom_right = transform_position(frustum.far_bottom_right, matrix); + + return transformed_frustum; +} \ No newline at end of file diff --git a/core/math.jai b/core/math.jai index ba1cc27..0608f4a 100644 --- a/core/math.jai +++ b/core/math.jai @@ -69,6 +69,16 @@ point_inside_aabb :: (aabb: AABB, point: Vector3) -> bool { && point.z >= aabb.min.z && point.z <= aabb.max.z; } +aabb_add :: (aabb: *AABB, point: Vector3) { + aabb.min.x = min(point.x, aabb.min.x); + aabb.min.y = min(point.y, aabb.min.y); + aabb.min.z = min(point.z, aabb.min.z); + + aabb.max.x = max(point.x, aabb.max.x); + aabb.max.y = max(point.y, aabb.max.y); + aabb.max.z = max(point.z, aabb.max.z); +} + operator == :: inline (a: Vector3i, b: Vector3i) -> bool { return a.x == b.x && a.y == b.y && a.z == b.z; } @@ -366,4 +376,5 @@ ease_in_out_sine :: (x: float) -> float { } #import "PCG"; -#import "Math"; \ No newline at end of file +#import "Math"; +#load "frustum.jai"; \ No newline at end of file diff --git a/core/scene.jai b/core/scene.jai index bb25455..7a7d189 100644 --- a/core/scene.jai +++ b/core/scene.jai @@ -102,7 +102,7 @@ create_scene :: (name: string, max_entities: s64 = 256) -> *Scene { array_reserve(*scene.entities, max_entities); scene.directional_light.color_and_intensity = .{1,1,1,1}; - scene.directional_light.direction = to_v4(normalize(Vector3.{0.3, -0.3, 0.5})); + scene.directional_light.direction = to_v4(normalize(Vector3.{0.2, -0.7, 0.4})); dir_light_data : Directional_Light_Buffer_Data; dir_light_data.color_and_intensity = scene.directional_light.color_and_intensity; diff --git a/module.jai b/module.jai index cd6d959..fa659e0 100644 --- a/module.jai +++ b/module.jai @@ -104,79 +104,12 @@ coven_run :: (game_update_proc: (float), game_update_post_physics_proc: (float)) SDL_Quit(); } -update_light_buffer :: () { - scene := current_scene; - light_data : Directional_Light_Buffer_Data; - light_data.direction = scene.directional_light.direction; - light_data.color_and_intensity = scene.directional_light.color_and_intensity; - - dir := to_v3(scene.directional_light.direction); - - z_near := 1.0; - z_far := 50.5; - width := 10.0; - light_projection := orthographic_lh_projection_matrix(-width, width, -width, width, z_near, z_far); - light_view : Matrix4; - eye := scene.directional_light.view_position - dir * 30.0; - - m := look_at_lh(eye, eye + dir * 5.0, .{0,1,0}); - - light_view = m; - - light_data.light_matrix = light_projection * light_view; - - upload_data_to_buffer(renderer, directional_light_buffer, *light_data, size_of(Directional_Light_Buffer_Data)); -} - -sync_engine_buffers :: () { - update_light_buffer(); - // Camera buffer - camera := *current_scene.camera; - - camera_data : Camera_Data; - camera_data.projection_matrix = camera.projection_matrix; - camera_data.view_matrix = camera.view_matrix; - camera_data.position = to_v4(camera.position); - upload_data_to_buffer(renderer, camera_buffer, *camera_data, size_of(Camera_Data)); - - shader_time : Shader_Time; - shader_time.time = time; - upload_data_to_buffer(renderer, time_buffer, *shader_time, size_of(Shader_Time)); - - // Sync entity transforms - for current_scene.entities { - if it.flags & .RENDERABLE { - if it.renderable.type == { - case .MODEL; { - for n, i: it.renderable.model.nodes { - if n.meshes.count > 0 { - node_data := *it.renderable.nodes[i]; - upload_data_to_buffer(renderer, node_data.transform_buffer, *node_data.transform.world_matrix, size_of(Matrix4)); - - if node_data.num_bones > 0 { - for handle, mesh_index: n.meshes { - m := parray_get(*renderer.meshes, handle); - bones : [MAX_BONES] Matrix4; - for bone_index: 0..m.num_bones-1 { - bone := *it.renderable.nodes[m.bone_indices[bone_index]]; - bones[bone_index] = bone.transform.world_matrix * m.bone_matrices[bone_index]; - } - upload_data_to_buffer(renderer, node_data.bone_buffers[mesh_index], bones.data, size_of(Matrix4) * m.num_bones); - } - } - } - } - } - } - } - } -} - #if NETWORKING { #load "networking/networking.jai"; } #load "input/input.jai"; +#load "renderer/engine_buffers.jai"; #load "renderer/renderer.jai"; #load "windowing/window.jai"; #load "physics/physics.jai"; diff --git a/renderer/engine_buffers.jai b/renderer/engine_buffers.jai new file mode 100644 index 0000000..9c843e8 --- /dev/null +++ b/renderer/engine_buffers.jai @@ -0,0 +1,91 @@ +calc_tight_light_projection :: (camera: Camera, light_direction: Vector3) -> Matrix4 { + // View space camera frustum + aspect_ratio := cast(float)renderer.render_target_height / cast(float)renderer.render_target_width; + frustum := get_frustum(camera.fov, aspect_ratio, camera.z_near, camera.z_far); + + // View frustum back to world space + inv_camera_view := inverse(camera.view_matrix); + view_frustum_in_world_space := transform(frustum, inv_camera_view); + + // Transform world space camera frustum to light space (with origin in 0,0,0) + light_view := look_at_lh(.{0,0,0}, light_direction, .{0,1,0}); + light_space_frustum := transform(view_frustum_in_world_space, light_view); + + aabb := get_frustum_aabb(light_space_frustum); + bottom_left := aabb.min; + top_right := Vector3.{aabb.max.x, aabb.max.y, aabb.min.z}; + light_pos_world := (bottom_left + top_right) * 0.5; + + inverse_light_view := inverse(light_view); + light_pos_world = transform_position(light_pos_world, inverse_light_view); + + light_view = look_at_lh(light_pos_world, light_pos_world + light_direction, .{0,1,0}); + light_space_frustum = transform(view_frustum_in_world_space, light_view); + + final_aabb := get_frustum_aabb(light_space_frustum); + // @Incomplete: Padding + + 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; +} + +update_light_buffer :: () { + scene := current_scene; + camera := scene.camera; + + light_data : Directional_Light_Buffer_Data; + light_data.direction = scene.directional_light.direction; + light_data.color_and_intensity = scene.directional_light.color_and_intensity; + + light_matrix := calc_tight_light_projection(camera, scene.directional_light.direction.xyz); + light_data.light_matrix = light_matrix; + + upload_data_to_buffer(renderer, directional_light_buffer, *light_data, size_of(Directional_Light_Buffer_Data)); +} + +sync_engine_buffers :: () { + update_light_buffer(); + + // Camera buffer + camera := *current_scene.camera; + + camera_data : Camera_Data; + camera_data.projection_matrix = camera.projection_matrix; + camera_data.view_matrix = camera.view_matrix; + camera_data.position = to_v4(camera.position); + upload_data_to_buffer(renderer, camera_buffer, *camera_data, size_of(Camera_Data)); + + shader_time : Shader_Time; + shader_time.time = time; + upload_data_to_buffer(renderer, time_buffer, *shader_time, size_of(Shader_Time)); + + // Sync entity transforms + for current_scene.entities { + if it.flags & .RENDERABLE { + if it.renderable.type == { + case .MODEL; { + for n, i: it.renderable.model.nodes { + if n.meshes.count > 0 { + node_data := *it.renderable.nodes[i]; + upload_data_to_buffer(renderer, node_data.transform_buffer, *node_data.transform.world_matrix, size_of(Matrix4)); + + if node_data.num_bones > 0 { + for handle, mesh_index: n.meshes { + m := parray_get(*renderer.meshes, handle); + bones : [MAX_BONES] Matrix4; + for bone_index: 0..m.num_bones-1 { + bone := *it.renderable.nodes[m.bone_indices[bone_index]]; + bones[bone_index] = bone.transform.world_matrix * m.bone_matrices[bone_index]; + } + upload_data_to_buffer(renderer, node_data.bone_buffers[mesh_index], bones.data, size_of(Matrix4) * m.num_bones); + } + } + } + } + } + } + } + } +} \ No newline at end of file