From 9d4b85c940a39d0d00a75636db6d7331097c0ba2 Mon Sep 17 00:00:00 2001 From: Draklaw Date: Wed, 9 Mar 2022 00:13:51 +0100 Subject: [PATCH] Camera + fix swapchain crash. --- CMakeLists.txt | 3 +- src/Camera.cpp | 70 ++++++++++++++++++ src/Camera.h | 92 ++++++++++++++++++++++++ src/{VulkanTutorial.cpp => Renderer.cpp} | 80 ++++++++------------- src/{VulkanTutorial.h => Renderer.h} | 22 +++--- src/VkExpe.cpp | 25 ++++--- src/VkExpe.h | 9 ++- src/vk/Swapchain.cpp | 6 +- 8 files changed, 223 insertions(+), 84 deletions(-) create mode 100644 src/Camera.cpp create mode 100644 src/Camera.h rename src/{VulkanTutorial.cpp => Renderer.cpp} (90%) rename src/{VulkanTutorial.h => Renderer.h} (84%) diff --git a/CMakeLists.txt b/CMakeLists.txt index f89fe28..7c29d86 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,10 +56,11 @@ add_executable(vk_expe src/vk/Swapchain.cpp src/main.cpp + src/Camera.cpp src/Simplex.cpp src/Planet.cpp src/VkExpe.cpp - src/VulkanTutorial.cpp + src/Renderer.cpp ) add_shaders(vk_expe diff --git a/src/Camera.cpp b/src/Camera.cpp new file mode 100644 index 0000000..721d83d --- /dev/null +++ b/src/Camera.cpp @@ -0,0 +1,70 @@ +// Copyright 2022 Simon Boyé + +#include + + +Camera::Camera() noexcept + : m_left(-1) + , m_right(1) + , m_top(-1) + , m_bottom(1) + , m_near(0.1) + , m_far(100) + , m_position(Vector3::Zero()) + , m_direction(Vector3::UnitZ()) + , m_down(Vector3::UnitY()) +{} + +Camera::~Camera() = default; + + +void Camera::set_projection(Real h_fov, Real width_height_ratio) noexcept { + const Real hx = std::tan(h_fov / Real(2)); + const Real hy = hx / width_height_ratio; + set_projection( + -hx, hx, + -hy, hy + ); +} + +void Camera::update_aspect_ratio(Real width_height_ratio) noexcept { + const Real prev_ratio = (m_right - m_left) / (m_bottom - m_top); + const Real next_ratio = width_height_ratio; + + const Real sx = (Real(1) + Real(1) / prev_ratio) / (Real(1) + Real(1) / next_ratio); + const Real sy = (Real(1) + prev_ratio) / (Real(1) + next_ratio); + + m_left *= sx; + m_right *= sx; + m_top *= sy; + m_bottom *= sy; +} + + +Matrix3 Camera::basis() const noexcept { + Matrix3 basis; + basis << m_down.cross(m_direction), m_down, m_direction; + return basis; +} + +Matrix4 Camera::view_matrix() const noexcept { + Matrix3 linear_view; + linear_view << + m_down.cross(m_direction).transpose(), + m_down.transpose(), + m_direction.transpose(); + Matrix4 view; + view << linear_view, linear_view * -m_position, + Vector4::UnitW().transpose(); + return view; +} + +Matrix4 Camera::projection_matrix() const noexcept { + return ::projection_matrix( + m_near * m_left, m_near * m_right, + m_near * m_top, m_near * m_bottom, + m_near, m_far + ); +} + + diff --git a/src/Camera.h b/src/Camera.h new file mode 100644 index 0000000..7914ce0 --- /dev/null +++ b/src/Camera.h @@ -0,0 +1,92 @@ +// Copyright 2022 Simon Boyé +#pragma once + +#include + + +class Camera { +public: + Camera() noexcept; + ~Camera(); + + inline Real left() const noexcept { + return m_left; + } + + inline Real right() const noexcept { + return m_right; + } + + inline Real top() const noexcept { + return m_top; + } + + inline Real bottom() const noexcept { + return m_bottom; + } + + void set_projection(Real left, Real right, Real top, Real bottom) noexcept { + m_left = left; + m_right = right; + m_top = top; + m_bottom = bottom; + } + void set_projection(Real h_fov, Real width_height_ratio) noexcept; + void update_aspect_ratio(Real width_height_ratio) noexcept; + + + inline Real near() const noexcept { + return m_near; + } + + inline Real far() const noexcept { + return m_far; + } + + void set_clip_distances(Real near, Real far) noexcept { + m_near = near; + m_far = far; + } + + + inline Vector3 position() const noexcept { + return m_position; + } + + inline void set_position(const Vector3& position) noexcept { + m_position = position; + } + + inline Vector3 direction() const noexcept { + return m_direction; + } + + inline void set_direction(const Vector3& direction) noexcept { + m_direction = direction; + } + + inline Vector3 down() const noexcept { + return m_down; + } + + inline void set_down(const Vector3& down) noexcept { + m_down = down; + } + + Matrix3 basis() const noexcept; + Matrix4 view_matrix() const noexcept; + Matrix4 projection_matrix() const noexcept; + +private: + Real m_left; + Real m_right; + Real m_top; + Real m_bottom; + + Real m_near; + Real m_far; + + Vector3 m_position; + Vector3 m_direction; + Vector3 m_down; +}; diff --git a/src/VulkanTutorial.cpp b/src/Renderer.cpp similarity index 90% rename from src/VulkanTutorial.cpp rename to src/Renderer.cpp index faa278e..3cc6652 100644 --- a/src/VulkanTutorial.cpp +++ b/src/Renderer.cpp @@ -1,5 +1,5 @@ // Copyright 2022 Simon Boyé -#include +#include #include @@ -98,9 +98,9 @@ struct Uniforms { }; -VulkanTutorial::VulkanTutorial() { +Renderer::Renderer() { m_swapchain.register_creation_callback( - std::bind(&VulkanTutorial::create_swapchain_objects, this)); + std::bind(&Renderer::create_swapchain_objects, this)); auto const subdiv_count = 4; @@ -151,13 +151,13 @@ VulkanTutorial::VulkanTutorial() { // abort(); } -VulkanTutorial::~VulkanTutorial() { +Renderer::~Renderer() { if(m_context) vkDeviceWaitIdle(m_context.device()); } -void VulkanTutorial::initialize(SDL_Window* window) { +void Renderer::initialize(SDL_Window* window) { auto const context_settings = vk::ContextSettings() #if defined(VKEXPE_ENABLE_VALIDATION) || !defined(NDEBUG) .with_debug(true) @@ -183,43 +183,19 @@ void VulkanTutorial::initialize(SDL_Window* window) { } -void VulkanTutorial::set_camera(const Vector3& camera_position, const Vector3& camera_z, const Vector3& camera_y) { - m_camera_position = camera_position; - m_camera_z = camera_z; - m_camera_y = camera_y; +void Renderer::set_camera(const Camera& camera) { + m_camera = camera; } -void VulkanTutorial::draw_frame() { +void Renderer::draw_frame() { m_swapchain.begin_frame(); const auto image_index = m_swapchain.current_image_index(); auto& image_states = m_image_states[image_index]; - const auto now = Clock::now(); - if(m_last_frame_time.time_since_epoch() != Duration(0)) { - m_time += now - m_last_frame_time; - } - m_last_frame_time = now; - - Matrix3 linear_view; - linear_view << - m_camera_y.cross(m_camera_z).transpose(), - m_camera_y.transpose(), - m_camera_z.transpose(); - Matrix4 view; - view << linear_view, linear_view * -m_camera_position, - Vector4::UnitW().transpose(); - - const float fov = M_PI / 3.0f; - const float near = 0.1f; - const float far = 10.0f; - const float hx = near * std::tan(fov / 2.0f); - const float hy = hx * m_swapchain.extent().height / m_swapchain.extent().width; - const Eigen::Matrix4f proj = projection_matrix( - -hx, hx, - -hy, hy, - near, far - ); + m_camera.update_aspect_ratio(Real(m_swapchain.extent().width) / Real(m_swapchain.extent().height)); + const Matrix4 view = m_camera.view_matrix(); + const Matrix4 proj = m_camera.projection_matrix(); Transform model = Transform::Identity(); @@ -293,12 +269,12 @@ void VulkanTutorial::draw_frame() { m_swapchain.swap_buffers(done_semaphores); } -void VulkanTutorial::invalidate_swapchain() { +void Renderer::invalidate_swapchain() { m_swapchain.invalidate(); } -void VulkanTutorial::create_swapchain_objects() { +void Renderer::create_swapchain_objects() { m_image_states.clear(); m_swapchain_states.~SwapchainStates(); @@ -311,7 +287,7 @@ void VulkanTutorial::create_swapchain_objects() { } -void VulkanTutorial::create_command_pool() { +void Renderer::create_command_pool() { m_command_pool = vk::CommandPool( m_context, m_context.queue_family(GRAPHIC_QUEUE) @@ -319,7 +295,7 @@ void VulkanTutorial::create_command_pool() { } -void VulkanTutorial::create_descriptor_set_layout() { +void Renderer::create_descriptor_set_layout() { VkDescriptorSetLayoutBinding binding[] { { .binding = 0, @@ -331,14 +307,14 @@ void VulkanTutorial::create_descriptor_set_layout() { m_descriptor_set_layout = vk::DescriptorSetLayout(m_context, binding); } -void VulkanTutorial::create_pipeline_layout() { +void Renderer::create_pipeline_layout() { VkDescriptorSetLayout set_layouts[] { m_descriptor_set_layout, }; m_pipeline_layout = vk::PipelineLayout(m_context, set_layouts); } -void VulkanTutorial::create_render_pass() { +void Renderer::create_render_pass() { VkAttachmentDescription color_attachment { .format = m_context.surface_format().format, .samples = VK_SAMPLE_COUNT_1_BIT, @@ -384,7 +360,7 @@ void VulkanTutorial::create_render_pass() { } -void VulkanTutorial::create_vertex_buffer() { +void Renderer::create_vertex_buffer() { VkDeviceSize size = sizeof(vertices[0]) * vertices.size(); m_vertex_buffer = vk::Buffer( m_context, @@ -396,7 +372,7 @@ void VulkanTutorial::create_vertex_buffer() { m_vertex_buffer.upload(size, vertices.data(), m_context.queue_family(GRAPHIC_QUEUE)); } -void VulkanTutorial::create_index_buffer() { +void Renderer::create_index_buffer() { VkDeviceSize size = sizeof(indices[0]) * indices.size(); m_index_buffer = vk::Buffer( m_context, @@ -409,13 +385,13 @@ void VulkanTutorial::create_index_buffer() { } -void VulkanTutorial::initialize_swapchain_states() { +void Renderer::initialize_swapchain_states() { create_descriptor_pool(); create_graphic_pipeline(); } -void VulkanTutorial::create_descriptor_pool() { +void Renderer::create_descriptor_pool() { VkDescriptorPoolSize pool_sizes[] { { .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, @@ -430,7 +406,7 @@ void VulkanTutorial::create_descriptor_pool() { ); } -void VulkanTutorial::create_graphic_pipeline() { +void Renderer::create_graphic_pipeline() { auto vertex_shader_module = vk::ShaderModule(m_context, "shaders/shader.vert.spv"); auto geometry_shader_module = vk::ShaderModule(m_context, "shaders/shader.geom.spv"); auto fragment_shader_module = vk::ShaderModule(m_context, "shaders/shader.frag.spv"); @@ -569,7 +545,7 @@ void VulkanTutorial::create_graphic_pipeline() { } -void VulkanTutorial::initialize_image_states(size_t image_index) { +void Renderer::initialize_image_states(size_t image_index) { auto& image_states = m_image_states[image_index]; image_states.m_image_index = image_index; @@ -586,7 +562,7 @@ void VulkanTutorial::initialize_image_states(size_t image_index) { } -void VulkanTutorial::create_framebuffer(ImageStates& image_states) { +void Renderer::create_framebuffer(ImageStates& image_states) { auto view = m_swapchain.image_view(image_states.m_image_index); image_states.m_framebuffer = vk::Framebuffer( m_context, @@ -597,7 +573,7 @@ void VulkanTutorial::create_framebuffer(ImageStates& image_states) { } -void VulkanTutorial::create_uniform_buffer(ImageStates& image_states) { +void Renderer::create_uniform_buffer(ImageStates& image_states) { const auto image_index = image_states.m_image_index; image_states.m_uniform_buffer = vk::Buffer( @@ -629,7 +605,7 @@ void VulkanTutorial::create_uniform_buffer(ImageStates& image_states) { ); } -void VulkanTutorial::create_descriptor_set(ImageStates& image_states) { +void Renderer::create_descriptor_set(ImageStates& image_states) { image_states.m_descriptor_set = vk::DescriptorSet( m_context, m_swapchain_states.m_descriptor_pool, @@ -657,7 +633,7 @@ void VulkanTutorial::create_descriptor_set(ImageStates& image_states) { ); } -void VulkanTutorial::create_draw_buffer(ImageStates& image_states) { +void Renderer::create_draw_buffer(ImageStates& image_states) { image_states.m_draw_buffer = vk::Buffer( m_context, DrawBufferOffset + MaxDrawTileCount * sizeof(VkDrawIndexedIndirectCommand), @@ -667,7 +643,7 @@ void VulkanTutorial::create_draw_buffer(ImageStates& image_states) { ); } -void VulkanTutorial::create_command_buffer(ImageStates& image_states) { +void Renderer::create_command_buffer(ImageStates& image_states) { image_states.m_command_buffer = vk::CommandBuffer(m_context, m_command_pool); VkCommandBufferBeginInfo begin_info { diff --git a/src/VulkanTutorial.h b/src/Renderer.h similarity index 84% rename from src/VulkanTutorial.h rename to src/Renderer.h index fb826c3..9cba2f3 100644 --- a/src/VulkanTutorial.h +++ b/src/Renderer.h @@ -1,6 +1,8 @@ // Copyright 2022 Simon Boyé #pragma once +#include + #include #include #include @@ -31,7 +33,7 @@ VkVertexInputBindingDescription vertex_binding_description(); std::array vertex_attributes_description(); -class VulkanTutorial { +class Renderer { public: enum QueueIndex { GRAPHIC_QUEUE, @@ -43,15 +45,15 @@ public: using SecondsD = std::chrono::duration; public: - VulkanTutorial(); - VulkanTutorial(const VulkanTutorial&) = delete; - ~VulkanTutorial(); + Renderer(); + Renderer(const Renderer&) = delete; + ~Renderer(); - VulkanTutorial& operator=(const VulkanTutorial&) = delete; + Renderer& operator=(const Renderer&) = delete; void initialize(SDL_Window* window); - void set_camera(const Vector3& camera_position, const Vector3& camera_z, const Vector3& camera_y); + void set_camera(const Camera& camera); void draw_frame(); void invalidate_swapchain(); @@ -130,11 +132,5 @@ private: }; std::vector m_image_states; - - Vector3 m_camera_position = Vector3(0.0f, 0.0f, -3.0f); - Vector3 m_camera_z = Vector3(0.0f, 0.0f, 1.0f); - Vector3 m_camera_y = Vector3(0.0f, 1.0f, 0.0f); - - TimePoint m_last_frame_time; - Duration m_time = Duration(0); + Camera m_camera; }; diff --git a/src/VkExpe.cpp b/src/VkExpe.cpp index a865317..d3f364b 100644 --- a/src/VkExpe.cpp +++ b/src/VkExpe.cpp @@ -15,6 +15,12 @@ void SdlWindowDeleter::operator()(SDL_Window* window) const { VkExpe::VkExpe(int argc, char** argv) { + m_camera.set_position(Vector3(0.0f, 0.0f, -3.0f)); + m_camera.set_direction(Vector3::UnitZ()); + m_camera.set_down(Vector3::UnitY()); + + m_camera.set_projection(M_PI / 3.0, 1.0); + m_camera.set_clip_distances(0.1, 10); } VkExpe::~VkExpe() { @@ -109,7 +115,7 @@ void VkExpe::run() { update(std::chrono::duration(elapsed).count()); - m_vulkan.set_camera(m_camera_position, m_camera_z, m_camera_y); + m_vulkan.set_camera(m_camera); m_vulkan.draw_frame(); m_mouse_offset = Vector2::Zero(); @@ -128,14 +134,16 @@ void VkExpe::update(double elapsed) { const Real x_sensi = 0.001; const Real y_sensi = -0.001; - const Vector3 camera_x = m_camera_y.cross(m_camera_z); + const Vector3 camera_z = m_camera.direction(); + const Vector3 camera_y = m_camera.down(); + const Vector3 camera_x = camera_y.cross(camera_z); Vector3 axis = - x_sensi * m_mouse_offset[0] * m_camera_y + + x_sensi * m_mouse_offset[0] * camera_y + y_sensi * m_mouse_offset[1] * camera_x; Real rot_norm = axis.norm(); AngleAxis rot(rot_norm, axis / rot_norm); - m_camera_y = rot * m_camera_y; - m_camera_z = rot * m_camera_z; + m_camera.set_down(rot * camera_y); + m_camera.set_direction(rot * camera_z); } Vector3 walk_direction = Vector3::Zero(); @@ -156,8 +164,9 @@ void VkExpe::update(double elapsed) { walk_direction.normalize(); const Real base_velocity = 1; - Matrix3 camera_basis; - camera_basis << m_camera_y.cross(m_camera_z), m_camera_y, m_camera_z; - m_camera_position += elapsed * base_velocity * (camera_basis * walk_direction); + const Matrix3 basis = m_camera.basis(); + m_camera.set_position( + m_camera.position() + elapsed * base_velocity * (basis * walk_direction) + ); } } diff --git a/src/VkExpe.h b/src/VkExpe.h index 23b49cf..bddb6ef 100644 --- a/src/VkExpe.h +++ b/src/VkExpe.h @@ -1,7 +1,8 @@ // Copyright 2022 Simon Boyé #pragma once -#include +#include +#include #include @@ -32,11 +33,9 @@ public: void update(double elapsed); private: - VulkanTutorial m_vulkan; + Renderer m_vulkan; - Vector3 m_camera_position = Vector3(0.0f, 0.0f, -3.0f); - Vector3 m_camera_z = Vector3(0.0f, 0.0f, 1.0f); - Vector3 m_camera_y = Vector3(0.0f, 1.0f, 0.0f); + Camera m_camera; WindowUP m_window; bool m_running = false; diff --git a/src/vk/Swapchain.cpp b/src/vk/Swapchain.cpp index 5f51f0e..c3c608b 100644 --- a/src/vk/Swapchain.cpp +++ b/src/vk/Swapchain.cpp @@ -332,11 +332,7 @@ void Swapchain::destroy() { callback(); m_frame_resources.clear(); - - for(auto& image_resources: m_image_resources) { - image_resources.render_done.destroy(); - image_resources.view.destroy(); - } + m_image_resources.clear(); m_context->destroy_swapchain(m_swapchain); }