From 027635634548a5818b7621fda38c974808dafc20 Mon Sep 17 00:00:00 2001 From: Tim Stullich Date: Wed, 16 Sep 2020 14:56:28 -0400 Subject: [PATCH] Added perspective camera as uniform buffer --- shaders/shader.vert | 8 +++- src/buffer.cpp | 6 +++ src/buffer.h | 10 +++++ src/camera.h | 9 ++++ src/renderer.cpp | 105 ++++++++++++++++++++++++++++++++++++++++++-- src/renderer.h | 17 +++++++ 6 files changed, 150 insertions(+), 5 deletions(-) create mode 100644 src/camera.h diff --git a/shaders/shader.vert b/shaders/shader.vert index 04eadee..1856a6e 100644 --- a/shaders/shader.vert +++ b/shaders/shader.vert @@ -1,12 +1,18 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable +layout(binding = 0) uniform Camera { + mat4 model; + mat4 view; + mat4 projection; +} cam; + layout(location = 0) in vec3 inPosition; layout(location = 1) in vec3 inColor; layout(location = 0) out vec3 fragColor; void main() { - gl_Position = vec4(inPosition, 1.0f); + gl_Position = cam.projection * cam.view * cam.model * vec4(inPosition, 1.0f); fragColor = inColor; } \ No newline at end of file diff --git a/src/buffer.cpp b/src/buffer.cpp index ee37b40..bcdbb20 100644 --- a/src/buffer.cpp +++ b/src/buffer.cpp @@ -139,3 +139,9 @@ void IndexBuffer::create(const BufferContext &ctx, const std::vector & vkFreeMemory(ctx.logicalDevice, stagingMemory, nullptr); } +void UniformBuffer::create(const BufferContext &ctx, const Camera &camera) { + VkDeviceSize bufferSize = sizeof(Camera); + + init(ctx, bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, buffer, deviceMemory); +} \ No newline at end of file diff --git a/src/buffer.h b/src/buffer.h index 7cdf73d..c6ac222 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -5,6 +5,7 @@ #include +#include "camera.h" #include "vertex.h" // TODO Templatize this logic since vertex and index buffer creation is almost identical @@ -21,6 +22,8 @@ class Buffer { void cleanup(VkDevice logicalDevice); + inline VkDeviceMemory getDeviceMemory() const { return deviceMemory; } + inline VkBuffer getBuffer() const { return buffer; } protected: @@ -48,4 +51,11 @@ class IndexBuffer : public Buffer { IndexBuffer() = default; void create(const BufferContext &ctx, const std::vector &vertIndices); +}; + +class UniformBuffer : public Buffer { +public: + UniformBuffer() = default; + + void create(const BufferContext &ctx, const Camera &camera); }; \ No newline at end of file diff --git a/src/camera.h b/src/camera.h new file mode 100644 index 0000000..4a4c8d7 --- /dev/null +++ b/src/camera.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +struct Camera { + glm::mat4 model; + glm::mat4 view; + glm::mat4 proj; +}; \ No newline at end of file diff --git a/src/renderer.cpp b/src/renderer.cpp index 64e444e..579d13e 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -19,7 +19,12 @@ Renderer::~Renderer() { vertexBuffer.cleanup(logicalDevice); vertIndexBuffer.cleanup(logicalDevice); + for (auto& uniformBuffer : uniformBuffers) { + uniformBuffer.cleanup(logicalDevice); + } + vkDestroyDescriptorPool(logicalDevice, descriptorPool, nullptr); + vkDestroyDescriptorSetLayout(logicalDevice, descriptorSetLayout, nullptr); for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { vkDestroySemaphore(logicalDevice, imageAvailableSemaphores[i], nullptr); @@ -86,13 +91,16 @@ bool Renderer::checkValidationLayerSupport() { // Destroys all the resources associated with swapchain recreation void Renderer::cleanupSwapchain() { + for (size_t i = 0; i < swapchain.getImagesSize(); ++i) { + uniformBuffers[i].cleanup(logicalDevice); + } + vkFreeCommandBuffers(logicalDevice, commandPool, static_cast(commandBuffers.size()), - commandBuffers.data()); + commandBuffers.data()); vkDestroyPipeline(logicalDevice, graphicsPipeline, nullptr); vkDestroyPipelineLayout(logicalDevice, graphicsPipelineLayout, nullptr); vkDestroyRenderPass(logicalDevice, renderPass, nullptr); - swapchain.cleanup(); } @@ -151,6 +159,8 @@ void Renderer::createCommandBuffers() { vkCmdBindIndexBuffer(commandBuffers[i], vertIndexBuffer.getBuffer(), 0, VK_INDEX_TYPE_UINT32); + vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineLayout, 0, 1, &descriptorSets[i], 0, nullptr); + vkCmdDrawIndexed(commandBuffers[i], static_cast(vertIndices.size()), 1, 0, 0, 0); vkCmdEndRenderPass(commandBuffers[i]); @@ -170,6 +180,7 @@ void Renderer::createCommandPool() { } } +// TODO Check if this is used by Dear IMGUI and how to move it void Renderer::createDescriptorPool() { VkDescriptorPoolSize poolSize = {}; poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; @@ -186,6 +197,55 @@ void Renderer::createDescriptorPool() { } } +void Renderer::createDescriptorSetLayout() { + VkDescriptorSetLayoutBinding layoutBinding = {}; + layoutBinding.binding = 0; + layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + layoutBinding.descriptorCount = 1; + layoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + + VkDescriptorSetLayoutCreateInfo layoutCreateInfo = {}; + layoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layoutCreateInfo.bindingCount = 1; + layoutCreateInfo.pBindings = &layoutBinding; + + if (vkCreateDescriptorSetLayout(logicalDevice, &layoutCreateInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) { + throw std::runtime_error("Unable to create descriptor set layouts!"); + } +} + +void Renderer::createDescriptorSets() { + std::vector layouts(swapchain.getImagesSize(), descriptorSetLayout); + VkDescriptorSetAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocInfo.descriptorPool = descriptorPool; + allocInfo.descriptorSetCount = static_cast(swapchain.getImagesSize()); + allocInfo.pSetLayouts = layouts.data(); + + descriptorSets.resize(swapchain.getImagesSize()); + if (vkAllocateDescriptorSets(logicalDevice, &allocInfo, descriptorSets.data()) != VK_SUCCESS) { + throw std::runtime_error("Unable to allocate descriptor sets!"); + } + + for (size_t i = 0; i < swapchain.getImagesSize(); ++i) { + VkDescriptorBufferInfo bufferInfo = {}; + bufferInfo.buffer = uniformBuffers[i].getBuffer(); + bufferInfo.offset = 0; + bufferInfo.range = sizeof(Camera); + + VkWriteDescriptorSet descriptorWrite{}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.dstSet = descriptorSets[i]; + descriptorWrite.dstBinding = 0; + descriptorWrite.dstArrayElement = 0; + descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptorWrite.descriptorCount = 1; + descriptorWrite.pBufferInfo = &bufferInfo; + + vkUpdateDescriptorSets(logicalDevice, 1, &descriptorWrite, 0, nullptr); + } +} + void Renderer::createGraphicsPipeline() { // Load our shader modules in from disk auto vertShaderCode = ShaderLoader::load("shaders/vert.spv"); @@ -256,7 +316,7 @@ void Renderer::createGraphicsPipeline() { rasterizerCreateInfo.rasterizerDiscardEnable = VK_FALSE; rasterizerCreateInfo.polygonMode = VK_POLYGON_MODE_FILL; rasterizerCreateInfo.cullMode = VK_CULL_MODE_BACK_BIT; - rasterizerCreateInfo.frontFace = VK_FRONT_FACE_CLOCKWISE; + rasterizerCreateInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; rasterizerCreateInfo.lineWidth = 1.0f; rasterizerCreateInfo.depthBiasEnable = VK_FALSE; rasterizerCreateInfo.depthBiasConstantFactor = 0.0f; @@ -294,6 +354,8 @@ void Renderer::createGraphicsPipeline() { // Create a pipeline layout VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {}; pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutCreateInfo.setLayoutCount = 1; + pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayout; if (vkCreatePipelineLayout(logicalDevice, &pipelineLayoutCreateInfo, nullptr, &graphicsPipelineLayout) != VK_SUCCESS) { @@ -543,6 +605,14 @@ UserInterface::UIContext Renderer::createUIContext() { return context; } +void Renderer::createUniformBuffers() { + Camera cam{}; + uniformBuffers.resize(swapchain.getImagesSize()); + for (size_t i = 0; i < swapchain.getImagesSize(); ++i) { + uniformBuffers[i].create(createBufferContext(), cam); + } +} + void Renderer::createVertexBuffer() { auto ctx = createBufferContext(); vertexBuffer.create(ctx, vertices); @@ -576,6 +646,8 @@ void Renderer::drawFrame() { // Record UI draw data auto uiCommandBuffer = ui.recordCommands(imageIndex, swapchain.getExtent()); + updateUniformBuffer(imageIndex); + VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; @@ -677,14 +749,17 @@ void Renderer::initVulkan() { createLogicalDevice(); createSwapchain(); createRenderPass(); + createDescriptorSetLayout(); createGraphicsPipeline(); swapchain.initFramebuffers(renderPass); createCommandPool(); createVertexBuffer(); createIndexBuffer(); + createUniformBuffers(); + createDescriptorPool(); + createDescriptorSets(); createCommandBuffers(); createSyncObjects(); - createDescriptorPool(); } void Renderer::initWindow() { @@ -788,6 +863,9 @@ void Renderer::recreateSwapchain() { createGraphicsPipeline(); swapchain.initFramebuffers(renderPass); createDescriptorPool(); + createUniformBuffers(); + createDescriptorPool(); + createDescriptorSets(); createCommandBuffers(); // We also need to take care of the UI @@ -817,4 +895,23 @@ void Renderer::setupDebugMessenger() { if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) { throw std::runtime_error("Failed to setup debug messenger!"); } +} + +void Renderer::updateUniformBuffer(size_t bufferIdx) { + static auto startTime = std::chrono::high_resolution_clock::now(); + + auto currentTime = std::chrono::high_resolution_clock::now(); + float time = std::chrono::duration(currentTime - startTime).count(); + + Camera cam{}; + auto extent = swapchain.getExtent(); + cam.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f)); + cam.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)); + cam.proj = glm::perspective(glm::radians(45.0f), extent.width / (float) extent.height, 0.1f, 10.0f); + cam.proj[1][1] *= -1; + + void* data; + vkMapMemory(logicalDevice, uniformBuffers[bufferIdx].getDeviceMemory(), 0, sizeof(cam), 0, &data); + memcpy(data, &cam, sizeof(cam)); + vkUnmapMemory(logicalDevice, uniformBuffers[bufferIdx].getDeviceMemory()); } \ No newline at end of file diff --git a/src/renderer.h b/src/renderer.h index c1e5d67..92d3bab 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -11,6 +12,10 @@ #define GLFW_INCLUDE_VULKAN #include +#define GLM_FORCE_RADIANS +#include +#include + #include "buffer.h" #include "gltfloader.h" #include "shaderloader.h" @@ -95,6 +100,10 @@ class Renderer { void createDescriptorPool(); + void createDescriptorSetLayout(); + + void createDescriptorSets(); + void createGraphicsPipeline(); void createIndexBuffer(); @@ -117,6 +126,8 @@ class Renderer { UserInterface::UIContext createUIContext(); + void createUniformBuffers(); + void createVertexBuffer(); void drawFrame(); @@ -139,6 +150,8 @@ class Renderer { void setupDebugMessenger(); + void updateUniformBuffer(size_t bufferIdx); + uint32_t windowWidth = 1920; uint32_t windowHeight = 1080; @@ -156,6 +169,8 @@ class Renderer { VertexBuffer vertexBuffer; IndexBuffer vertIndexBuffer; + std::vector uniformBuffers; + VkRenderPass renderPass = {}; VkPipeline graphicsPipeline = {}; @@ -172,6 +187,8 @@ class Renderer { std::vector imagesInFlight; VkDescriptorPool descriptorPool = {}; + VkDescriptorSetLayout descriptorSetLayout = {}; + std::vector descriptorSets = {}; Swapchain swapchain;