Browse Source

Camera + fix swapchain crash.

master
Draklaw 4 years ago
parent
commit
9d4b85c940
  1. 3
      CMakeLists.txt
  2. 70
      src/Camera.cpp
  3. 92
      src/Camera.h
  4. 80
      src/Renderer.cpp
  5. 22
      src/Renderer.h
  6. 25
      src/VkExpe.cpp
  7. 9
      src/VkExpe.h
  8. 6
      src/vk/Swapchain.cpp

3
CMakeLists.txt

@ -56,10 +56,11 @@ add_executable(vk_expe
src/vk/Swapchain.cpp src/vk/Swapchain.cpp
src/main.cpp src/main.cpp
src/Camera.cpp
src/Simplex.cpp src/Simplex.cpp
src/Planet.cpp src/Planet.cpp
src/VkExpe.cpp src/VkExpe.cpp
src/VulkanTutorial.cpp src/Renderer.cpp
) )
add_shaders(vk_expe add_shaders(vk_expe

70
src/Camera.cpp

@ -0,0 +1,70 @@
// Copyright 2022 Simon Boyé
#include <Camera.h>
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
);
}

92
src/Camera.h

@ -0,0 +1,92 @@
// Copyright 2022 Simon Boyé
#pragma once
#include <core/math.h>
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;
};

80
src/VulkanTutorial.cpp → src/Renderer.cpp

@ -1,5 +1,5 @@
// Copyright 2022 Simon Boyé // Copyright 2022 Simon Boyé
#include <VulkanTutorial.h> #include <Renderer.h>
#include <Planet.h> #include <Planet.h>
@ -98,9 +98,9 @@ struct Uniforms {
}; };
VulkanTutorial::VulkanTutorial() { Renderer::Renderer() {
m_swapchain.register_creation_callback( m_swapchain.register_creation_callback(
std::bind(&VulkanTutorial::create_swapchain_objects, this)); std::bind(&Renderer::create_swapchain_objects, this));
auto const subdiv_count = 4; auto const subdiv_count = 4;
@ -151,13 +151,13 @@ VulkanTutorial::VulkanTutorial() {
// abort(); // abort();
} }
VulkanTutorial::~VulkanTutorial() { Renderer::~Renderer() {
if(m_context) if(m_context)
vkDeviceWaitIdle(m_context.device()); vkDeviceWaitIdle(m_context.device());
} }
void VulkanTutorial::initialize(SDL_Window* window) { void Renderer::initialize(SDL_Window* window) {
auto const context_settings = vk::ContextSettings() auto const context_settings = vk::ContextSettings()
#if defined(VKEXPE_ENABLE_VALIDATION) || !defined(NDEBUG) #if defined(VKEXPE_ENABLE_VALIDATION) || !defined(NDEBUG)
.with_debug(true) .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) { void Renderer::set_camera(const Camera& camera) {
m_camera_position = camera_position; m_camera = camera;
m_camera_z = camera_z;
m_camera_y = camera_y;
} }
void VulkanTutorial::draw_frame() { void Renderer::draw_frame() {
m_swapchain.begin_frame(); m_swapchain.begin_frame();
const auto image_index = m_swapchain.current_image_index(); const auto image_index = m_swapchain.current_image_index();
auto& image_states = m_image_states[image_index]; auto& image_states = m_image_states[image_index];
const auto now = Clock::now(); m_camera.update_aspect_ratio(Real(m_swapchain.extent().width) / Real(m_swapchain.extent().height));
if(m_last_frame_time.time_since_epoch() != Duration(0)) { const Matrix4 view = m_camera.view_matrix();
m_time += now - m_last_frame_time; const Matrix4 proj = m_camera.projection_matrix();
}
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
);
Transform model = Transform::Identity(); Transform model = Transform::Identity();
@ -293,12 +269,12 @@ void VulkanTutorial::draw_frame() {
m_swapchain.swap_buffers(done_semaphores); m_swapchain.swap_buffers(done_semaphores);
} }
void VulkanTutorial::invalidate_swapchain() { void Renderer::invalidate_swapchain() {
m_swapchain.invalidate(); m_swapchain.invalidate();
} }
void VulkanTutorial::create_swapchain_objects() { void Renderer::create_swapchain_objects() {
m_image_states.clear(); m_image_states.clear();
m_swapchain_states.~SwapchainStates(); 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_command_pool = vk::CommandPool(
m_context, m_context,
m_context.queue_family(GRAPHIC_QUEUE) 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[] { VkDescriptorSetLayoutBinding binding[] {
{ {
.binding = 0, .binding = 0,
@ -331,14 +307,14 @@ void VulkanTutorial::create_descriptor_set_layout() {
m_descriptor_set_layout = vk::DescriptorSetLayout(m_context, binding); m_descriptor_set_layout = vk::DescriptorSetLayout(m_context, binding);
} }
void VulkanTutorial::create_pipeline_layout() { void Renderer::create_pipeline_layout() {
VkDescriptorSetLayout set_layouts[] { VkDescriptorSetLayout set_layouts[] {
m_descriptor_set_layout, m_descriptor_set_layout,
}; };
m_pipeline_layout = vk::PipelineLayout(m_context, set_layouts); m_pipeline_layout = vk::PipelineLayout(m_context, set_layouts);
} }
void VulkanTutorial::create_render_pass() { void Renderer::create_render_pass() {
VkAttachmentDescription color_attachment { VkAttachmentDescription color_attachment {
.format = m_context.surface_format().format, .format = m_context.surface_format().format,
.samples = VK_SAMPLE_COUNT_1_BIT, .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(); VkDeviceSize size = sizeof(vertices[0]) * vertices.size();
m_vertex_buffer = vk::Buffer( m_vertex_buffer = vk::Buffer(
m_context, m_context,
@ -396,7 +372,7 @@ void VulkanTutorial::create_vertex_buffer() {
m_vertex_buffer.upload(size, vertices.data(), m_context.queue_family(GRAPHIC_QUEUE)); 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(); VkDeviceSize size = sizeof(indices[0]) * indices.size();
m_index_buffer = vk::Buffer( m_index_buffer = vk::Buffer(
m_context, 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_descriptor_pool();
create_graphic_pipeline(); create_graphic_pipeline();
} }
void VulkanTutorial::create_descriptor_pool() { void Renderer::create_descriptor_pool() {
VkDescriptorPoolSize pool_sizes[] { VkDescriptorPoolSize pool_sizes[] {
{ {
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .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 vertex_shader_module = vk::ShaderModule(m_context, "shaders/shader.vert.spv");
auto geometry_shader_module = vk::ShaderModule(m_context, "shaders/shader.geom.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"); 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]; auto& image_states = m_image_states[image_index];
image_states.m_image_index = 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); auto view = m_swapchain.image_view(image_states.m_image_index);
image_states.m_framebuffer = vk::Framebuffer( image_states.m_framebuffer = vk::Framebuffer(
m_context, 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; const auto image_index = image_states.m_image_index;
image_states.m_uniform_buffer = vk::Buffer( 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( image_states.m_descriptor_set = vk::DescriptorSet(
m_context, m_context,
m_swapchain_states.m_descriptor_pool, 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( image_states.m_draw_buffer = vk::Buffer(
m_context, m_context,
DrawBufferOffset + MaxDrawTileCount * sizeof(VkDrawIndexedIndirectCommand), 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); image_states.m_command_buffer = vk::CommandBuffer(m_context, m_command_pool);
VkCommandBufferBeginInfo begin_info { VkCommandBufferBeginInfo begin_info {

22
src/VulkanTutorial.h → src/Renderer.h

@ -1,6 +1,8 @@
// Copyright 2022 Simon Boyé // Copyright 2022 Simon Boyé
#pragma once #pragma once
#include <Camera.h>
#include <vk/Swapchain.h> #include <vk/Swapchain.h>
#include <vk/DescriptorSet.h> #include <vk/DescriptorSet.h>
#include <vk/DescriptorPool.h> #include <vk/DescriptorPool.h>
@ -31,7 +33,7 @@ VkVertexInputBindingDescription vertex_binding_description();
std::array<VkVertexInputAttributeDescription, 4> vertex_attributes_description(); std::array<VkVertexInputAttributeDescription, 4> vertex_attributes_description();
class VulkanTutorial { class Renderer {
public: public:
enum QueueIndex { enum QueueIndex {
GRAPHIC_QUEUE, GRAPHIC_QUEUE,
@ -43,15 +45,15 @@ public:
using SecondsD = std::chrono::duration<double>; using SecondsD = std::chrono::duration<double>;
public: public:
VulkanTutorial(); Renderer();
VulkanTutorial(const VulkanTutorial&) = delete; Renderer(const Renderer&) = delete;
~VulkanTutorial(); ~Renderer();
VulkanTutorial& operator=(const VulkanTutorial&) = delete; Renderer& operator=(const Renderer&) = delete;
void initialize(SDL_Window* window); 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 draw_frame();
void invalidate_swapchain(); void invalidate_swapchain();
@ -130,11 +132,5 @@ private:
}; };
std::vector<ImageStates> m_image_states; std::vector<ImageStates> m_image_states;
Camera m_camera;
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);
}; };

25
src/VkExpe.cpp

@ -15,6 +15,12 @@ void SdlWindowDeleter::operator()(SDL_Window* window) const {
VkExpe::VkExpe(int argc, char** argv) { 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() { VkExpe::~VkExpe() {
@ -109,7 +115,7 @@ void VkExpe::run() {
update(std::chrono::duration<double>(elapsed).count()); update(std::chrono::duration<double>(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_vulkan.draw_frame();
m_mouse_offset = Vector2::Zero(); m_mouse_offset = Vector2::Zero();
@ -128,14 +134,16 @@ void VkExpe::update(double elapsed) {
const Real x_sensi = 0.001; const Real x_sensi = 0.001;
const Real y_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 = 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; y_sensi * m_mouse_offset[1] * camera_x;
Real rot_norm = axis.norm(); Real rot_norm = axis.norm();
AngleAxis rot(rot_norm, axis / rot_norm); AngleAxis rot(rot_norm, axis / rot_norm);
m_camera_y = rot * m_camera_y; m_camera.set_down(rot * camera_y);
m_camera_z = rot * m_camera_z; m_camera.set_direction(rot * camera_z);
} }
Vector3 walk_direction = Vector3::Zero(); Vector3 walk_direction = Vector3::Zero();
@ -156,8 +164,9 @@ void VkExpe::update(double elapsed) {
walk_direction.normalize(); walk_direction.normalize();
const Real base_velocity = 1; const Real base_velocity = 1;
Matrix3 camera_basis; const Matrix3 basis = m_camera.basis();
camera_basis << m_camera_y.cross(m_camera_z), m_camera_y, m_camera_z; m_camera.set_position(
m_camera_position += elapsed * base_velocity * (camera_basis * walk_direction); m_camera.position() + elapsed * base_velocity * (basis * walk_direction)
);
} }
} }

9
src/VkExpe.h

@ -1,7 +1,8 @@
// Copyright 2022 Simon Boyé // Copyright 2022 Simon Boyé
#pragma once #pragma once
#include <VulkanTutorial.h> #include <Renderer.h>
#include <Camera.h>
#include <core/math.h> #include <core/math.h>
@ -32,11 +33,9 @@ public:
void update(double elapsed); void update(double elapsed);
private: private:
VulkanTutorial m_vulkan; Renderer m_vulkan;
Vector3 m_camera_position = Vector3(0.0f, 0.0f, -3.0f); Camera m_camera;
Vector3 m_camera_z = Vector3(0.0f, 0.0f, 1.0f);
Vector3 m_camera_y = Vector3(0.0f, 1.0f, 0.0f);
WindowUP m_window; WindowUP m_window;
bool m_running = false; bool m_running = false;

6
src/vk/Swapchain.cpp

@ -332,11 +332,7 @@ void Swapchain::destroy() {
callback(); callback();
m_frame_resources.clear(); m_frame_resources.clear();
m_image_resources.clear();
for(auto& image_resources: m_image_resources) {
image_resources.render_done.destroy();
image_resources.view.destroy();
}
m_context->destroy_swapchain(m_swapchain); m_context->destroy_swapchain(m_swapchain);
} }

Loading…
Cancel
Save