Camera + fix swapchain crash.
This commit is contained in:
@@ -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
|
||||
|
||||
70
src/Camera.cpp
Normal file
70
src/Camera.cpp
Normal file
@@ -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
Normal file
92
src/Camera.h
Normal file
@@ -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;
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright 2022 Simon Boyé
|
||||
#include <VulkanTutorial.h>
|
||||
#include <Renderer.h>
|
||||
|
||||
#include <Planet.h>
|
||||
|
||||
@@ -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 {
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright 2022 Simon Boyé
|
||||
#pragma once
|
||||
|
||||
#include <Camera.h>
|
||||
|
||||
#include <vk/Swapchain.h>
|
||||
#include <vk/DescriptorSet.h>
|
||||
#include <vk/DescriptorPool.h>
|
||||
@@ -31,7 +33,7 @@ VkVertexInputBindingDescription vertex_binding_description();
|
||||
std::array<VkVertexInputAttributeDescription, 4> vertex_attributes_description();
|
||||
|
||||
|
||||
class VulkanTutorial {
|
||||
class Renderer {
|
||||
public:
|
||||
enum QueueIndex {
|
||||
GRAPHIC_QUEUE,
|
||||
@@ -43,15 +45,15 @@ public:
|
||||
using SecondsD = std::chrono::duration<double>;
|
||||
|
||||
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<ImageStates> 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;
|
||||
};
|
||||
@@ -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<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_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)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// Copyright 2022 Simon Boyé
|
||||
#pragma once
|
||||
|
||||
#include <VulkanTutorial.h>
|
||||
#include <Renderer.h>
|
||||
#include <Camera.h>
|
||||
|
||||
#include <core/math.h>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user