diff --git a/assets/engine/shaders/ssao.comp b/assets/engine/shaders/ssao.comp index 6309674c..a76cc3fc 100644 --- a/assets/engine/shaders/ssao.comp +++ b/assets/engine/shaders/ssao.comp @@ -68,6 +68,9 @@ struct Camera { mat4 view_matrix; mat4 projection_matrix; mat4 view_projection; + mat4 inverse_view_matrix; + mat4 inverse_projection_matrix; + mat4 inverse_view_projection; }; layout(set=0,binding=0,scalar) buffer readonly CameraBuffer { @@ -84,7 +87,7 @@ vec3 get_view_position(vec2 uv) { uv /= textureSize(depth, 0).xy; float depth_value = texture(depth, uv).r; vec4 clip_space = vec4(uv * 2.0 - 1.0, depth_value, 1.0); - vec4 view_space = inverse(camera.projection_matrix) * clip_space; + vec4 view_space = camera.inverse_projection_matrix * clip_space; view_space /= view_space.w; return view_space.xyz; } @@ -93,7 +96,7 @@ vec3 get_view_position(ivec2 coords) { float depth_value = texelFetch(depth, coords, 0).r; vec2 uv = (vec2(coords) + vec2(0.5)) / vec2(textureSize(depth, 0).xy); vec4 clip_space = vec4(uv * 2.0 - 1.0, depth_value, 1.0); - vec4 view_space = inverse(camera.projection_matrix) * clip_space; + vec4 view_space = camera.inverse_projection_matrix * clip_space; view_space /= view_space.w; return view_space.xyz; } diff --git a/src/math.rs b/src/math.rs index 0df1889c..1c2b63ae 100644 --- a/src/math.rs +++ b/src/math.rs @@ -60,8 +60,46 @@ pub fn from_normal(normal: crate::Vector3) -> maths_rs::Mat4f { )) } +/// Left handed row major 4x4 matrix inverse +pub fn inverse(m: maths_rs::Mat4f) -> maths_rs::Mat4f { + let mut inv = maths_rs::Mat4f::default(); + + inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10]; + inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10]; + inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9]; + inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9]; + inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10]; + inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10]; + inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9]; + inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9]; + inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6]; + inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6]; + inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5]; + inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5]; + inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6]; + inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6]; + inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] - m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5]; + inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5]; + + let det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12]; + + if det == 0f32 { + panic!("Matrix is not invertible"); + } + + let det = 1.0 / det; + + for i in 0..16 { + inv[i] = inv[i] * det; + } + + inv +} + #[cfg(test)] mod tests { + use maths_rs::mat::{MatInverse, MatTranspose}; + #[test] fn test_from_normal() { let value = super::from_normal(crate::Vector3::new(0f32, 0f32, 1f32)); @@ -96,4 +134,62 @@ mod tests { maths_rs::Vec4f::from((0f32, 0f32, 0f32, 1f32)), ))); } + + #[test] + fn test_inverse_matrix() { + let value = maths_rs::Mat4f::from(( + maths_rs::Vec4f::from((1f32, 0f32, 0f32, 0f32)), + maths_rs::Vec4f::from((0f32, 1f32, 0f32, 0f32)), + maths_rs::Vec4f::from((0f32, 0f32, 1f32, 0f32)), + maths_rs::Vec4f::from((0f32, 0f32, 0f32, 1f32)), + )); + let value = super::inverse(value); + assert_eq!(value, maths_rs::Mat4f::from(( + maths_rs::Vec4f::from((1f32, 0f32, 0f32, 0f32)), + maths_rs::Vec4f::from((0f32, 1f32, 0f32, 0f32)), + maths_rs::Vec4f::from((0f32, 0f32, 1f32, 0f32)), + maths_rs::Vec4f::from((0f32, 0f32, 0f32, 1f32)), + ))); + + let value = maths_rs::Mat4f::from(( + maths_rs::Vec4f::from((1f32, 0f32, 0f32, 0f32)), + maths_rs::Vec4f::from((0f32, 2f32, 0f32, 0f32)), + maths_rs::Vec4f::from((0f32, 0f32, 3f32, 0f32)), + maths_rs::Vec4f::from((0f32, 0f32, 0f32, 1f32)), + )); + let value = super::inverse(value); + assert_eq!(value, maths_rs::Mat4f::from(( + maths_rs::Vec4f::from((1f32, 0f32, 0f32, 0f32)), + maths_rs::Vec4f::from((0f32, 0.5f32, 0f32, 0f32)), + maths_rs::Vec4f::from((0f32, 0f32, 1f32 / 3f32, 0f32)), + maths_rs::Vec4f::from((0f32, 0f32, 0f32, 1f32)), + ))); + + let nearly_equal = |a: f32, b: f32| (a - b).abs() < 0.0001f32; + + let value = maths_rs::Mat4f::from(( + maths_rs::Vec4f::from((1f32, 2f32, 3f32, 4f32)), + maths_rs::Vec4f::from((5f32, 1f32, 6f32, 7f32)), + maths_rs::Vec4f::from((8f32, 9f32, 1f32, 10f32)), + maths_rs::Vec4f::from((11f32, 12f32, 13f32, 1f32)), + )); + let value = value.inverse(); + + assert!(nearly_equal(value[0], -212f32/507.0f32)); + assert!(nearly_equal(value[1], 55f32/338f32)); + assert!(nearly_equal(value[2], 157f32/3042f32)); + assert!(nearly_equal(value[3], 53f32/3042f32)); + assert!(nearly_equal(value[4], 103f32/507f32)); + assert!(nearly_equal(value[5], -61f32/338f32)); + assert!(nearly_equal(value[6], 127f32/3042f32)); + assert!(nearly_equal(value[7], 101f32/3042f32)); + assert!(nearly_equal(value[8], 79f32/507f32)); + assert!(nearly_equal(value[9], 9f32/338f32)); + assert!(nearly_equal(value[10], -257f32/3042f32)); + assert!(nearly_equal(value[11], 107f32/3042f32)); + assert!(nearly_equal(value[12], 23f32/169f32)); + assert!(nearly_equal(value[13], 5f32/169f32)); + assert!(nearly_equal(value[14], 5f32/169f32)); + assert!(nearly_equal(value[15], -8f32/169f32)); + } } \ No newline at end of file diff --git a/src/rendering/visibility_model/render_domain.rs b/src/rendering/visibility_model/render_domain.rs index 506bccd2..845baca7 100644 --- a/src/rendering/visibility_model/render_domain.rs +++ b/src/rendering/visibility_model/render_domain.rs @@ -4,7 +4,7 @@ use std::rc::Rc; use std::sync::RwLock; use log::error; -use maths_rs::mat::{MatProjection, MatRotate3D}; +use maths_rs::mat::{MatInverse, MatProjection, MatRotate3D}; use maths_rs::{prelude::MatTranslate, Mat4f}; use crate::core::entity::EntityBuilder; @@ -216,7 +216,7 @@ impl VisibilityWorldRenderDomain { diffuse = ghi_instance.create_image(Some("diffuse"), Extent::new(1920, 1080, 1), ghi::Formats::RGBA16(ghi::Encodings::UnsignedNormalized), None, ghi::Uses::RenderTarget | ghi::Uses::Storage | ghi::Uses::TransferDestination, ghi::DeviceAccesses::GpuRead, ghi::UseCases::DYNAMIC); depth_target = ghi_instance.create_image(Some("depth_target"), Extent::new(1920, 1080, 1), ghi::Formats::Depth32, None, ghi::Uses::DepthStencil | ghi::Uses::Image, ghi::DeviceAccesses::GpuRead, ghi::UseCases::DYNAMIC); - camera_data_buffer_handle = ghi_instance.create_buffer(Some("Visibility Camera Data"), 16 * 4 * 4, ghi::Uses::Storage, ghi::DeviceAccesses::CpuWrite | ghi::DeviceAccesses::GpuRead, ghi::UseCases::DYNAMIC); + camera_data_buffer_handle = ghi_instance.create_buffer(Some("Visibility Camera Data"), std::mem::size_of::<[ShaderCameraData; 8]>(), ghi::Uses::Storage, ghi::DeviceAccesses::CpuWrite | ghi::DeviceAccesses::GpuRead, ghi::UseCases::DYNAMIC); meshes_data_buffer = ghi_instance.create_buffer(Some("Visibility Meshes Data"), std::mem::size_of::<[ShaderInstanceData; MAX_INSTANCES]>(), ghi::Uses::Storage, ghi::DeviceAccesses::CpuWrite | ghi::DeviceAccesses::GpuRead, ghi::UseCases::STATIC); meshlets_data_buffer = ghi_instance.create_buffer(Some("Visibility Meshlets Data"), std::mem::size_of::<[ShaderMeshletData; MAX_MESHLETS]>(), ghi::Uses::Storage, ghi::DeviceAccesses::CpuWrite | ghi::DeviceAccesses::GpuRead, ghi::UseCases::STATIC); @@ -613,17 +613,14 @@ impl VisibilityWorldRenderDomain { let view_projection_matrix = projection_matrix * view_matrix; - struct ShaderCameraData { - view_matrix: maths_rs::Mat4f, - projection_matrix: maths_rs::Mat4f, - view_projection_matrix: maths_rs::Mat4f, - } - let camera_data_reference = unsafe { (camera_data_buffer.as_mut_ptr() as *mut ShaderCameraData).as_mut().unwrap() }; camera_data_reference.view_matrix = view_matrix; camera_data_reference.projection_matrix = projection_matrix; camera_data_reference.view_projection_matrix = view_projection_matrix; + camera_data_reference.inverse_view_matrix = math::inverse(view_matrix); + camera_data_reference.inverse_projection_matrix = math::inverse(projection_matrix); + camera_data_reference.inverse_view_projection_matrix = math::inverse(view_projection_matrix); command_buffer_recording.start_region("Visibility Render Model"); @@ -702,6 +699,17 @@ struct LightingData { lights: [LightData; MAX_LIGHTS], } +#[repr(C)] +#[derive(Copy, Clone)] +struct ShaderCameraData { + view_matrix: maths_rs::Mat4f, + projection_matrix: maths_rs::Mat4f, + view_projection_matrix: maths_rs::Mat4f, + inverse_view_matrix: maths_rs::Mat4f, + inverse_projection_matrix: maths_rs::Mat4f, + inverse_view_projection_matrix: maths_rs::Mat4f, +} + #[repr(C)] #[derive(Copy, Clone)] struct LightData { @@ -1486,6 +1494,9 @@ pub const CAMERA_STRUCT_GLSL: &'static str = "struct Camera { mat4 view; mat4 projection_matrix; mat4 view_projection; + mat4 inverse_view_matrix; + mat4 inverse_projection_matrix; + mat4 inverse_view_projection_matrix; };"; pub const MESHLET_STRUCT_GLSL: &'static str = "struct Meshlet {