Shadows
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
68
core/frustum.jai
Normal file
68
core/frustum.jai
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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";
|
||||
#import "Math";
|
||||
#load "frustum.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;
|
||||
|
||||
69
module.jai
69
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";
|
||||
|
||||
91
renderer/engine_buffers.jai
Normal file
91
renderer/engine_buffers.jai
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user