diff --git a/CMakeLists.txt b/CMakeLists.txt index 42f6dc6..4c326c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,7 @@ add_custom_target(compile_shaders ALL DEPENDS ${SPIRV_SHADERS}) add_executable(vulkan_test main.cpp vulkan/vulkan_app.cpp + vulkan/vulkan_glfw_events.cpp vulkan/vulkan_app.hpp ) diff --git a/vulkan/vulkan_app.cpp b/vulkan/vulkan_app.cpp index 4aa9906..ee30a06 100644 --- a/vulkan/vulkan_app.cpp +++ b/vulkan/vulkan_app.cpp @@ -219,6 +219,7 @@ namespace vapp{ VkPhysicalDeviceFeatures deviceFeatures{}; deviceFeatures.samplerAnisotropy = VK_TRUE; + deviceFeatures.sampleRateShading = VK_TRUE; VkDeviceCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; @@ -554,6 +555,8 @@ namespace vapp{ multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisampling.sampleShadingEnable = VK_FALSE; multisampling.rasterizationSamples = msaaSamples; + multisampling.sampleShadingEnable = VK_TRUE; + multisampling.minSampleShading = .8f; VkPipelineColorBlendAttachmentState colorBlendAttachment{}; colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT @@ -759,9 +762,8 @@ namespace vapp{ if(tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures & features) == features){ return format; } - - throw std::runtime_error("Func: findSupportedFormat\nError: Failed to find supported Format!\n"); } + throw std::runtime_error("Func: findSupportedFormat\nError: Failed to find supported Format!\n"); } VkFormat Vulkan::findDepthFormat(){ @@ -1435,8 +1437,8 @@ namespace vapp{ UniformBufferObject ubo{}; // INFO: Change here for other angles - ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(60.0f), glm::vec3(0.0f, 0.0f, 1.0f)); - ubo.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)); + ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(0.0f), glm::vec3(0.0f, 0.0f, 1.0f)); + ubo.view = glm::lookAt(cameraPos, cameraFront, cameraUp); ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float)swapChainExtent.height, 0.1f, 10.0f); // removing this line results in the image rendering upside down @@ -1543,6 +1545,13 @@ namespace vapp{ app->framebufferResized = true; } + static void handleMouseInputCallback(GLFWwindow* window, double xpos, double ypos) { + Vulkan* vulkan = static_cast(glfwGetWindowUserPointer(window)); + if (vulkan) { + vulkan->handleMouseInput(window, xpos, ypos); + } + } + void Vulkan::initWindow(const char *windowName){ glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); // tell glfw to not use opengl @@ -1550,6 +1559,9 @@ namespace vapp{ this->window = glfwCreateWindow(static_cast(_width), static_cast(_height), windowName, nullptr, nullptr); glfwSetWindowUserPointer(window, this); glfwSetFramebufferSizeCallback(window, framebufferResizeCallback); + + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_CAPTURED); + glfwSetCursorPosCallback(window, handleMouseInputCallback); } void Vulkan::initVulkan(){ @@ -1584,6 +1596,9 @@ namespace vapp{ while(!glfwWindowShouldClose(this->window)){ // glfwSwapBuffers(window); glfwPollEvents(); + + handleKeyboardInput(); + drawFrame(); } vkDeviceWaitIdle(device); diff --git a/vulkan/vulkan_app.hpp b/vulkan/vulkan_app.hpp index e6b5e27..40c4b35 100644 --- a/vulkan/vulkan_app.hpp +++ b/vulkan/vulkan_app.hpp @@ -27,16 +27,35 @@ #include #include -namespace vapp{ +namespace vapp +{ + class Camera + { + private: + glm::mat4 projectionMatrix{1.f}; + glm::mat4 viewMatrix{1.f}; + + public: + void setOthographicProjection(float left, float right, float bottom, float top); + void setPerspectiveProjection(float fovy, float aspect, float zNear, float zFar); + void setViewDirection(glm::vec3 position, glm::vec3 direction, glm::vec3 up); + void setViewTarget(glm::vec3 position, glm::vec3 target, glm::vec3 up); + void setViewYXZ(glm::vec3 position, glm::vec3 rotation); + const glm::mat4& getProjectionMatrix(); + const glm::mat4& getViewMatrix(); + }; + // Change here for other presentMode const VkPresentModeKHR WISHED_PRESENT_MODE = VK_PRESENT_MODE_MAILBOX_KHR; - struct Vertex{ + struct Vertex + { glm::vec3 pos; glm::vec3 color; glm::vec2 texCoord; - static VkVertexInputBindingDescription getBindingDescription(){ + static VkVertexInputBindingDescription getBindingDescription() + { VkVertexInputBindingDescription bindingDescription{}; bindingDescription.binding = 0; @@ -46,7 +65,8 @@ namespace vapp{ return bindingDescription; } - static std::array getAttributeDescriptions(){ + static std::array getAttributeDescriptions() + { std::array attributeDescriptions{}; attributeDescriptions[0].binding = 0; @@ -67,7 +87,8 @@ namespace vapp{ return attributeDescriptions; } - bool operator==(const Vertex &other) const{ + bool operator==(const Vertex& other) const + { return pos == other.pos && color == other.color && texCoord == other.texCoord; } }; @@ -93,22 +114,26 @@ namespace vapp{ */ // END Remove - struct UniformBufferObject{ + struct UniformBufferObject + { alignas(16) glm::mat4 model; alignas(16) glm::mat4 view; alignas(16) glm::mat4 proj; }; - struct QueueFamilyIndices{ + struct QueueFamilyIndices + { std::optional graphicsFamily; std::optional presentFamily; - bool isComplete(){ + bool isComplete() + { return graphicsFamily.has_value(); } }; - struct SwapChainSupportDetails{ + struct SwapChainSupportDetails + { VkSurfaceCapabilitiesKHR capabilities; std::vector formats; std::vector presentModes; @@ -118,10 +143,11 @@ namespace vapp{ static std::array getAttributeDescription(); - class Vulkan{ + class Vulkan + { private: #pragma region PrivateFields - GLFWwindow *window; + GLFWwindow* window; uint32_t _width, _height; VkInstance instance; @@ -213,22 +239,28 @@ namespace vapp{ void createRenderPass(); void createFramebuffers(); void createCommandPool(); - VkFormat findSupportedFormat(const std::vector &candidates, VkImageTiling tiling, VkFormatFeatureFlags features); + VkFormat findSupportedFormat(const std::vector& candidates, VkImageTiling tiling, + VkFormatFeatureFlags features); VkFormat findDepthFormat(); void createColorResources(); void createDepthResources(); VkCommandBuffer beginSingleTimeCommands(); void endSingleTimeCommands(VkCommandBuffer commandBuffer); - void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels); + void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, + uint32_t mipLevels); void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height); - void createImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkSampleCountFlagBits numSamples, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory &imageMemory); - void generateMipmaps(VkImage image, VkFormat imageFormat, int32_t texWidth, int32_t texHeight, uint32_t mipLevels); + void createImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkSampleCountFlagBits numSamples, + VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, + VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory); + void generateMipmaps(VkImage image, VkFormat imageFormat, int32_t texWidth, int32_t texHeight, + uint32_t mipLevels); void createTextureImage(); VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, uint32_t mipLevels); void createTextureImageView(); void createTextureSampler(); uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); - void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, VkDeviceMemory &bufferMemory); + void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, + VkBuffer& buffer, VkDeviceMemory& bufferMemory); void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size); void copyBufferOld(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size); void loadModel(); @@ -244,11 +276,12 @@ namespace vapp{ void drawFrame(); void cleanupSwapChain(); void recreateSwapChain(); - void initWindow(const char *windowName); + void initWindow(const char* windowName); void initVulkan(); void mainLoop(); void cleanup(); #pragma endregion + public: #pragma region PublicFields #ifdef DEBUG @@ -262,19 +295,39 @@ namespace vapp{ std::string TEXTURE_PATH; VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT; + + float yaw = -90.0f; + float pitch = 0.0f; + float lastX = 400.0f; + float lastY = 300.0f; + bool firstMouse = true; + + glm::vec3 cameraPos = glm::vec3(2.0f, 2.0f, 2.0f); + glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, 0.0f); + glm::vec3 cameraUp = glm::vec3(0.0f, 0.0f, 1.0f); #pragma endregion + #pragma region PublicFunctions - void run(const char *windowName, const uint32_t width = 800, const uint32_t height = 600); + void run(const char* windowName, const uint32_t width = 800, const uint32_t height = 600); +#pragma endregion + +#pragma region GLFWFunctions + void handleKeyboardInput(); + void handleMouseInput(GLFWwindow* window, double xpos, double ypos); #pragma endregion }; } // vapp -namespace std{ - template<> struct hash{ - size_t operator()(vapp::Vertex const &vertex) const{ +namespace std +{ + template <> + struct hash + { + size_t operator()(vapp::Vertex const& vertex) const + { return ((hash()(vertex.pos) ^ (hash()(vertex.color) << 1)) >> 1) ^ - (hash()(vertex.texCoord) << 1); + (hash()(vertex.texCoord) << 1); } }; } diff --git a/vulkan/vulkan_glfw_events.cpp b/vulkan/vulkan_glfw_events.cpp new file mode 100644 index 0000000..b9bd9f5 --- /dev/null +++ b/vulkan/vulkan_glfw_events.cpp @@ -0,0 +1,120 @@ +#include "vulkan_app.hpp" + +namespace vapp{ + + void Camera::setOthographicProjection(float left, float right, float bottom, float top){ + + } + + void Camera::setPerspectiveProjection(float fovy, float aspect, float zNear, float zFar){ + + } + + void Camera::setViewDirection(glm::vec3 position, glm::vec3 direction, glm::vec3 up) { + const glm::vec3 w{glm::normalize(direction)}; + const glm::vec3 u{glm::normalize(glm::cross(w, up))}; + const glm::vec3 v{glm::cross(w, u)}; + + viewMatrix = glm::mat4{1.f}; + viewMatrix[0][0] = u.x; + viewMatrix[1][0] = u.y; + viewMatrix[2][0] = u.z; + viewMatrix[0][1] = v.x; + viewMatrix[1][1] = v.y; + viewMatrix[2][1] = v.z; + viewMatrix[0][2] = w.x; + viewMatrix[1][2] = w.y; + viewMatrix[2][2] = w.z; + viewMatrix[3][0] = -glm::dot(u, position); + viewMatrix[3][1] = -glm::dot(v, position); + viewMatrix[3][2] = -glm::dot(w, position); + } + + void Camera::setViewTarget(glm::vec3 position, glm::vec3 target, glm::vec3 up) { + setViewDirection(position, target - position, up); + } + + void Camera::setViewYXZ(glm::vec3 position, glm::vec3 rotation) { + const float c3 = glm::cos(rotation.z); + const float s3 = glm::sin(rotation.z); + const float c2 = glm::cos(rotation.x); + const float s2 = glm::sin(rotation.x); + const float c1 = glm::cos(rotation.y); + const float s1 = glm::sin(rotation.y); + const glm::vec3 u{(c1 * c3 + s1 * s2 * s3), (c2 * s3), (c1 * s2 * s3 - c3 * s1)}; + const glm::vec3 v{(c3 * s1 * s2 - c1 * s3), (c2 * c3), (c1 * c3 * s2 + s1 * s3)}; + const glm::vec3 w{(c2 * s1), (-s2), (c1 * c2)}; + viewMatrix = glm::mat4{1.f}; + viewMatrix[0][0] = u.x; + viewMatrix[1][0] = u.y; + viewMatrix[2][0] = u.z; + viewMatrix[0][1] = v.x; + viewMatrix[1][1] = v.y; + viewMatrix[2][1] = v.z; + viewMatrix[0][2] = w.x; + viewMatrix[1][2] = w.y; + viewMatrix[2][2] = w.z; + viewMatrix[3][0] = -glm::dot(u, position); + viewMatrix[3][1] = -glm::dot(v, position); + viewMatrix[3][2] = -glm::dot(w, position); + } + + void Vulkan::handleKeyboardInput(){ + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS){ + cameraPos.x += 0.001f; + } + if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS){ + cameraPos.x -= 0.001f; + } + if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS){ + cameraPos.y -= 0.001f; + } + if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS){ + cameraPos.y += 0.001f; + } + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS){ + cameraPos.x += 0.001f; + } + if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS){ + cameraPos.x -= 0.001f; + } + if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS){ + cameraPos.z += 0.001f; + } + if (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS){ + cameraPos.z -= 0.001f; + } + } + + void Vulkan::handleMouseInput(GLFWwindow* window, double xpos, double ypos){ + double xoffset = xpos - (_width / 2.0); + double yoffset = ypos - (_height / 2.0); + + glfwSetCursorPos(window, _width / 2.0, _height / 2.0); + + float sensitivity = 0.001f; + xoffset *= sensitivity; + yoffset *= sensitivity; + + // Winkel aktualisieren + yaw += xoffset; + pitch += yoffset; + + // Optional: pitch begrenzen + if(pitch > 89.0f) + pitch = 89.0f; + if(pitch < -89.0f) + pitch = -89.0f; + + // Berechnung des neuen Richtungsvektors + glm::vec3 direction; + direction.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch)); + direction.y = sin(glm::radians(pitch)); + direction.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch)); + direction = glm::normalize(direction); + + // Der neue "Look-at"-Punkt ergibt sich aus der Kameraposition plus diesem Richtungsvektor + cameraFront = cameraPos + direction; + + } +} \ No newline at end of file