From 95527a5a558ca2edaf8e91d90da4ae62a428aa6f Mon Sep 17 00:00:00 2001 From: Benjamin Kraft Date: Sat, 21 Sep 2024 23:30:25 +0200 Subject: [PATCH] camera control --- include/{vulkan => }/application.hpp | 6 ++- include/camera.hpp | 28 +++++++++++ include/input.hpp | 44 +++++++++++++++++ include/simulation.hpp | 2 +- shaders/shader.comp | 2 +- src/camera.cpp | 60 +++++++++++++++++++++++ src/input.cpp | 73 ++++++++++++++++++++++++++++ src/soft_body.cpp | 2 +- src/vulkan/application.cpp | 20 ++++---- src/vulkan/command_pool.cpp | 2 +- 10 files changed, 225 insertions(+), 14 deletions(-) rename include/{vulkan => }/application.hpp (93%) create mode 100644 include/camera.hpp create mode 100644 include/input.hpp create mode 100644 src/camera.cpp create mode 100644 src/input.cpp diff --git a/include/vulkan/application.hpp b/include/application.hpp similarity index 93% rename from include/vulkan/application.hpp rename to include/application.hpp index 47821db..5a5168d 100644 --- a/include/vulkan/application.hpp +++ b/include/application.hpp @@ -13,6 +13,8 @@ #include #include #include +#include +#include class Instance; class Swapchain; @@ -23,13 +25,13 @@ class Image; class ComputePipeline; class Fence; class Semaphore; +class Camera; class Application { public: explicit Application(); void mainLoop(); ~Application(); - protected: Swapchain* swapchain = nullptr; Pipeline* graphicsPipeline = nullptr; @@ -52,4 +54,6 @@ protected: virtual void recordComputeCommands(VkCommandBuffer cmdBuffer) {} void update(); void createSyncObjects(); + + Camera* camera = nullptr; }; diff --git a/include/camera.hpp b/include/camera.hpp new file mode 100644 index 0000000..7a17e9a --- /dev/null +++ b/include/camera.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include +#include "input.hpp" + +class Camera : private MouseListener { +private: + glm::vec3 position {0, 0, 0}; + + float phi = 0; + float theta = 0; + + float fov = 45; + float near = 0.1; + float far = 100; + + VkExtent2D& extent; +public: + explicit Camera(VkExtent2D& extent); + void update(float dt); + glm::mat4 view() const; + glm::mat4 projection() const; + glm::vec3 localToWorld(const glm::vec3& direction) const; +protected: + void mouseMoved(float deltaX, float deltaY) override; +}; \ No newline at end of file diff --git a/include/input.hpp b/include/input.hpp new file mode 100644 index 0000000..55d937a --- /dev/null +++ b/include/input.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include + +class Listener; +class MouseListener; + +class Input { + friend Listener; + friend MouseListener; +public: + explicit Input(GLFWwindow* window); + static Input* instance; + static std::map KeyIsDown; + static std::map MouseButtonIsDown; +private: + GLFWwindow* window; + std::set listeners; + + void keyPressed(int key); + void keyReleased(int key); + + void mouseButtonPressed(int button); + void mouseButtonReleased(int button); + void mouseMoved(double newX, double newY); + double oldX {}, oldY {}; +}; + +class Listener { +public: + Listener(); + virtual ~Listener(); +}; + +class KeyListener : Listener { + +}; + +class MouseListener : public Listener { +public: + virtual void mouseMoved(float deltaX, float deltaY) {}; +}; \ No newline at end of file diff --git a/include/simulation.hpp b/include/simulation.hpp index 7df0159..1f71855 100644 --- a/include/simulation.hpp +++ b/include/simulation.hpp @@ -1,6 +1,6 @@ #pragma once -#include "vulkan/application.hpp" +#include "application.hpp" class SoftBody; class Buffer; diff --git a/shaders/shader.comp b/shaders/shader.comp index 9f0e2dc..2c9f359 100644 --- a/shaders/shader.comp +++ b/shaders/shader.comp @@ -12,5 +12,5 @@ layout (std140, set = 0, binding = 0) buffer VertexBuffer { }; void main() { - // vertices[0].position.z += 0.001; + } \ No newline at end of file diff --git a/src/camera.cpp b/src/camera.cpp new file mode 100644 index 0000000..f307b28 --- /dev/null +++ b/src/camera.cpp @@ -0,0 +1,60 @@ +#include "camera.hpp" +#include "application.hpp" +#include "vulkan/instance.hpp" +#include "input.hpp" +#include + +const std::map moveDirections { + {GLFW_KEY_A, {-1, 0, 0}}, + {GLFW_KEY_D, {1, 0, 0}}, + {GLFW_KEY_S, {0, 0, 1}}, + {GLFW_KEY_W, {0, 0, -1}}, + {GLFW_KEY_E, {0, 1, 0}}, + {GLFW_KEY_Q, {0, -1, 0}}, +}; + +void Camera::update(float dt) { + glm::vec3 add {}; + + for (const auto &[key, dir] : moveDirections) + if (Input::KeyIsDown[key]) + add += dir; + + position += localToWorld(add) * dt; +} + +glm::mat4 Camera::view() const { + glm::vec3 forward = localToWorld({0, 0, -1}); + return glm::lookAt(position, position + forward, glm::vec3(0, 1, 0)); +} + +glm::mat4 Camera::projection() const { + float aspect = static_cast(extent.width) / static_cast(extent.height); + return glm::perspective(glm::radians(fov), aspect, near, far); +} + +glm::vec3 Camera::localToWorld(const glm::vec3& direction) const { + float x = glm::sin(phi) * glm::cos(theta); + float y = glm::sin(theta); + float z = -glm::cos(phi) * glm::cos(theta); + glm::vec3 forward {x, y, z}; + glm::qua rotation = glm::quatLookAt(forward, glm::vec3(0, 1, 0)); + return rotation * direction; +} + +Camera::Camera(VkExtent2D &extent) : extent(extent) { + +} + +void Camera::mouseMoved(float deltaX, float deltaY) { + if (!Input::MouseButtonIsDown[GLFW_MOUSE_BUTTON_RIGHT]) + return; + + const float div = 300; + + phi += deltaX / div; + theta += -deltaY / div; + + float margin = 0.1; + theta = glm::clamp(theta, -glm::half_pi() + margin, glm::half_pi() - margin); +} diff --git a/src/input.cpp b/src/input.cpp new file mode 100644 index 0000000..d729724 --- /dev/null +++ b/src/input.cpp @@ -0,0 +1,73 @@ +#include "input.hpp" + +std::map Input::KeyIsDown; +std::map Input::MouseButtonIsDown; + +Input* Input::instance; + +Input::Input(GLFWwindow *window) : window(window) { + instance = this; + + glfwSetWindowUserPointer(window, this); + glfwSetKeyCallback(window, [](GLFWwindow* window, int key, int scancode, int action, int mods){ + auto inputManager = reinterpret_cast(glfwGetWindowUserPointer(window)); + if (action == GLFW_PRESS) + inputManager->keyPressed(key); + if (action == GLFW_RELEASE) + inputManager->keyReleased(key); + }); + + glfwSetCursorPosCallback(window, [](GLFWwindow* window, double xpos, double ypos){ + auto inputManager = reinterpret_cast(glfwGetWindowUserPointer(window)); + inputManager->mouseMoved(xpos, ypos); + }); + glfwGetCursorPos(window, &oldX, &oldY); + + glfwSetMouseButtonCallback(window, [](GLFWwindow* window, int button, int action, int mods){ + auto inputManager = reinterpret_cast(glfwGetWindowUserPointer(window)); + if (action == GLFW_PRESS) + inputManager->mouseButtonPressed(button); + if (action == GLFW_RELEASE) + inputManager->mouseButtonReleased(button); + }); +} + +void Input::keyPressed(int key) { + Input::KeyIsDown[key] = true; +} + +void Input::keyReleased(int key) { + Input::KeyIsDown[key] = false; +} + +void Input::mouseButtonPressed(int button) { + Input::MouseButtonIsDown[button] = true; + if (button == GLFW_MOUSE_BUTTON_RIGHT) + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); +} + +void Input::mouseButtonReleased(int button) { + Input::MouseButtonIsDown[button] = false; + if (button == GLFW_MOUSE_BUTTON_RIGHT) + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); +} + +void Input::mouseMoved(double newX, double newY) { + float deltaX = static_cast(newX - oldX); + float deltaY = static_cast(newY - oldY); + for (auto listener : listeners){ + if (auto mouseListener = dynamic_cast(listener)){ + mouseListener->mouseMoved(deltaX, deltaY); + } + } + oldX = newX; + oldY = newY; +} + +Listener::Listener() { + Input::instance->listeners.insert(this); +} + +Listener::~Listener() { + Input::instance->listeners.erase(this); +} diff --git a/src/soft_body.cpp b/src/soft_body.cpp index 21003e3..be41633 100644 --- a/src/soft_body.cpp +++ b/src/soft_body.cpp @@ -65,7 +65,7 @@ SoftBody::SoftBody(Mesh* mesh, float compliance) : compliance(compliance) { uint32_t a = out.trifacelist[i * 3 + 0]; uint32_t b = out.trifacelist[i * 3 + 1]; uint32_t c = out.trifacelist[i * 3 + 2]; - if (out.trifacemarkerlist[i] != 0) + if (out.trifacemarkerlist[i] != 1) faces.emplace_back(Face(a, b, c)); } faces.shrink_to_fit(); diff --git a/src/vulkan/application.cpp b/src/vulkan/application.cpp index 2b61442..c4adf31 100644 --- a/src/vulkan/application.cpp +++ b/src/vulkan/application.cpp @@ -1,4 +1,4 @@ -#include "vulkan/application.hpp" +#include "application.hpp" #include "vulkan/swapchain.hpp" #include "vulkan/pipeline.hpp" #include "vulkan/instance.hpp" @@ -6,12 +6,13 @@ #include "vulkan/command_pool.hpp" #include "vulkan/image.hpp" #include "vulkan/synchronization.hpp" - -#include - +#include "camera.hpp" +#include "input.hpp" Application::Application() { new Instance; + new Input(Instance::instance->window); + createSyncObjects(); swapchain = new Swapchain(); graphicsPipeline = new Pipeline(swapchain->renderPass); @@ -25,6 +26,7 @@ Application::Application() { graphicsPipeline->updateDescriptor(0, uniformBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); computePipeline = new ComputePipeline(); + camera = new Camera(swapchain->extent); char* stats; vmaBuildStatsString(Instance::instance->allocator, &stats, VK_TRUE); @@ -38,11 +40,9 @@ void Application::updateUniformBuffer() { elapsed += 0.007; UniformBufferObject ubo {}; - ubo.model = glm::rotate(glm::mat4(1), elapsed * glm::radians(90.f), glm::vec3(0, 0, 1)); - ubo.view = glm::lookAt(glm::vec3(5), glm::vec3(0), glm::vec3(0, 0, 1)); - ubo.projection = glm::perspective(glm::radians(45.f), - static_cast(swapchain->extent.width) / static_cast(swapchain->extent.height), - 0.1f, 10.f); + ubo.model = glm::mat4(1); + ubo.view = camera->view(); + ubo.projection = camera->projection(); ubo.projection[1][1] *= -1; memcpy(uniformBuffer->allocationInfo.pMappedData, &ubo, sizeof(UniformBufferObject)); @@ -125,6 +125,7 @@ void Application::drawFrame() { vkResetCommandBuffer(Instance::instance->commandPool->graphicsBuffer, 0); recordGraphicsCommandBuffer(imageIndex); + camera->update(0.017); updateUniformBuffer(); VkSubmitInfo submitInfo {}; @@ -198,6 +199,7 @@ Application::~Application() { delete uniformBuffer; delete graphicsPipeline; delete computePipeline; + delete camera; delete Instance::instance; } diff --git a/src/vulkan/command_pool.cpp b/src/vulkan/command_pool.cpp index 30a5186..0c4ad7f 100644 --- a/src/vulkan/command_pool.cpp +++ b/src/vulkan/command_pool.cpp @@ -1,5 +1,5 @@ #include "vulkan/command_pool.hpp" -#include "vulkan/application.hpp" +#include "application.hpp" #include "vulkan/instance.hpp" CommandPool::CommandPool() {