diff --git a/include/camera.h b/include/camera.h new file mode 100644 index 0000000..df5ed62 --- /dev/null +++ b/include/camera.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +class Camera { +public: + glm::vec3 position, target; +}; diff --git a/include/renderer.h b/include/renderer.h index 246ab0a..dffbf90 100644 --- a/include/renderer.h +++ b/include/renderer.h @@ -19,11 +19,11 @@ struct RenderTarget { VkImage* offscreenColorImages = nullptr; VkDeviceMemory* offscreenColorMemory = nullptr; VkImageView* offscreenColorImageViews = nullptr; - + VkImage* offscreenDepthImages = nullptr; VkDeviceMemory* offscreenDepthMemory = nullptr; VkImageView* offscreenDepthImageViews = nullptr; - + VkFramebuffer* offscreenFramebuffers = nullptr; VkCommandBuffer* commandBuffers = nullptr; @@ -37,17 +37,18 @@ struct RenderTarget { class World; class Mesh; +class Camera; class Renderer { public: Renderer(); ~Renderer(); - void render(World& world, RenderTarget* target); + void render(World& world, Camera& camera, RenderTarget* target); RenderTarget* createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTarget* oldRenderTarget = nullptr); void destroyRenderTarget(RenderTarget* target); - + void takeScreenshot(RenderTarget* target); VkShaderModule createShader(const char* path); diff --git a/include/worldpass.h b/include/worldpass.h index 075f319..d7ee281 100644 --- a/include/worldpass.h +++ b/include/worldpass.h @@ -5,13 +5,14 @@ class Renderer; class World; struct RenderTarget; +class Camera; class WorldPass { public: WorldPass(Renderer& renderer); ~WorldPass(); - void render(VkCommandBuffer commandBuffer, World& world, RenderTarget* target); + void render(VkCommandBuffer commandBuffer, World& world, Camera& camera, RenderTarget* target); VkRenderPass getRenderPass() const { return renderPass_; @@ -23,17 +24,17 @@ private: void createPipeline(); void createUniformBuffer(); void createDescriptorSet(); - + VkRenderPass renderPass_ = nullptr; - + VkDescriptorSetLayout setLayout_ = nullptr; - + VkPipelineLayout pipelineLayout_ = nullptr; VkPipeline pipeline_ = nullptr; - + VkDeviceMemory lightMemory_ = nullptr; VkBuffer lightBuffer_ = nullptr; - + VkDescriptorSet descriptorSet_ = nullptr; Renderer& renderer_; diff --git a/src/main.cpp b/src/main.cpp index 233a710..1bbd4a2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,6 +13,7 @@ #include "world.h" #include "mesh.h" #include "light.h" +#include "camera.h" SDL_Window* window = nullptr; @@ -145,6 +146,10 @@ int main(int, char*[]) { world.lights.push_back(light); + Camera camera; + camera.position.y = 1; + camera.position.z = 3; + bool running = true; while(running) { SDL_Event event = {}; @@ -174,7 +179,9 @@ int main(int, char*[]) { } } - renderer->render(world, target); + camera.position.x = sin(platform::getTime() / 500.0f); + + renderer->render(world, camera, target); } delete light; diff --git a/src/renderer.cpp b/src/renderer.cpp index 8701389..dc653b2 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -10,6 +10,7 @@ #include "platform.h" #include "mesh.h" +#include "camera.h" Renderer::Renderer() { createInstance(); @@ -47,12 +48,12 @@ Renderer::~Renderer() { vkDestroyInstance(instance_, nullptr); } -void Renderer::render(World& world, RenderTarget* target) { +void Renderer::render(World& world, Camera& camera, RenderTarget* target) { vkAcquireNextImageKHR(device_, target->swapchain, UINT64_MAX, target->imageAvailableSemaphore, nullptr, &target->currentImage); vkWaitForFences(device_, 1, &target->fences[target->currentImage], true, UINT64_MAX); vkResetFences(device_, 1, &target->fences[target->currentImage]); - + const VkCommandBuffer commandBuffer = target->commandBuffers[target->currentImage]; VkCommandBufferBeginInfo beginInfo = {}; @@ -72,7 +73,7 @@ void Renderer::render(World& world, RenderTarget* target) { vkCmdSetScissor(commandBuffer, 0, 1, &scissor); - worldPass_->render(commandBuffer, world, target); + worldPass_->render(commandBuffer, world, camera, target); VkClearValue clearColor = {}; @@ -258,7 +259,7 @@ RenderTarget* Renderer::createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTa vkCreateImageView(device_, &createInfo, nullptr, &target->offscreenColorImageViews[i]); } - + // offscreen depth image { VkImageCreateInfo imageCreateInfo = {}; @@ -273,21 +274,21 @@ RenderTarget* Renderer::createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTa imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - + vkCreateImage(device_, &imageCreateInfo, nullptr, &target->offscreenDepthImages[i]); - + VkMemoryRequirements memoryRequirements = {}; vkGetImageMemoryRequirements(device_, target->offscreenDepthImages[i], &memoryRequirements); - + VkMemoryAllocateInfo allocateInfo = {}; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = memoryRequirements.size; allocateInfo.memoryTypeIndex = findMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - + vkAllocateMemory(device_, &allocateInfo, nullptr, &target->offscreenDepthMemory[i]); vkBindImageMemory(device_, target->offscreenDepthImages[i], target->offscreenDepthMemory[i], 0); } - + // offscreen depth image view { VkImageViewCreateInfo createInfo = {}; @@ -298,7 +299,7 @@ RenderTarget* Renderer::createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTa createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; createInfo.subresourceRange.levelCount = 1; createInfo.subresourceRange.layerCount = 1; - + vkCreateImageView(device_, &createInfo, nullptr, &target->offscreenDepthImageViews[i]); } @@ -308,7 +309,7 @@ RenderTarget* Renderer::createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTa target->offscreenColorImageViews[i], target->offscreenDepthImageViews[i] }; - + VkFramebufferCreateInfo framebufferInfo = {}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferInfo.renderPass = worldPass_->getRenderPass(); @@ -371,11 +372,11 @@ void Renderer::destroyRenderTarget(RenderTarget* target) { for(uint32_t i = 0; i < target->numImages; i++) { vkDestroyFramebuffer(device_, target->offscreenFramebuffers[i], nullptr); - + vkDestroyImageView(device_, target->offscreenDepthImageViews[i], nullptr); vkFreeMemory(device_, target->offscreenDepthMemory[i], nullptr); vkDestroyImage(device_, target->offscreenDepthImages[i], nullptr); - + vkDestroyImageView(device_, target->offscreenColorImageViews[i], nullptr); vkFreeMemory(device_, target->offscreenColorMemory[i], nullptr); vkDestroyImage(device_, target->offscreenColorImages[i], nullptr); @@ -383,7 +384,7 @@ void Renderer::destroyRenderTarget(RenderTarget* target) { vkDestroyFramebuffer(device_, target->swapchainFramebuffers[i], nullptr); vkDestroyImageView(device_, target->swapchainImageViews[i], nullptr); } - + delete[] target->offscreenFramebuffers; delete[] target->offscreenDepthImageViews; delete[] target->offscreenDepthMemory; @@ -395,7 +396,7 @@ void Renderer::destroyRenderTarget(RenderTarget* target) { delete[] target->swapchainFramebuffers; delete[] target->swapchainImageViews; delete[] target->swapchainImages; - + delete[] target->postSets; vkDestroySwapchainKHR(device_, target->swapchain, nullptr); @@ -416,35 +417,35 @@ void Renderer::takeScreenshot(RenderTarget* target) { imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageCreateInfo.tiling = VK_IMAGE_TILING_LINEAR; imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; - + VkImage image = nullptr; vkCreateImage(device_, &imageCreateInfo, nullptr, &image); - + VkMemoryRequirements memoryRequirements = {}; vkGetImageMemoryRequirements(device_, image, &memoryRequirements); - + VkMemoryAllocateInfo allocateInfo = {}; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = memoryRequirements.size; allocateInfo.memoryTypeIndex = findMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); - + VkDeviceMemory imageMemory = nullptr; vkAllocateMemory(device_, &allocateInfo, nullptr, &imageMemory); vkBindImageMemory(device_, image, imageMemory, 0); - + VkCommandBufferAllocateInfo bufferAllocateInfo = {}; bufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; bufferAllocateInfo.commandPool = commandPool_; bufferAllocateInfo.commandBufferCount = 1; - + VkCommandBuffer commandBuffer = nullptr; vkAllocateCommandBuffers(device_, &bufferAllocateInfo, &commandBuffer); - + VkCommandBufferBeginInfo beginInfo = {}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - + vkBeginCommandBuffer(commandBuffer, &beginInfo); - + // change screenshot image to transfer dst layout { VkImageMemoryBarrier imageMemoryBarrier = {}; @@ -455,7 +456,7 @@ void Renderer::takeScreenshot(RenderTarget* target) { imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageMemoryBarrier.subresourceRange.layerCount = 1; imageMemoryBarrier.subresourceRange.levelCount = 1; - + vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, @@ -465,9 +466,9 @@ void Renderer::takeScreenshot(RenderTarget* target) { 0, nullptr, 1, &imageMemoryBarrier); } - + const VkImage srcImage = target->swapchainImages[0]; // FIXME: use previous image - + // change offscreen image to transfer src layout { VkImageMemoryBarrier imageMemoryBarrier = {}; @@ -480,7 +481,7 @@ void Renderer::takeScreenshot(RenderTarget* target) { imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageMemoryBarrier.subresourceRange.layerCount = 1; imageMemoryBarrier.subresourceRange.levelCount = 1; - + vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, @@ -490,7 +491,7 @@ void Renderer::takeScreenshot(RenderTarget* target) { 0, nullptr, 1, &imageMemoryBarrier); } - + VkImageCopy imageCopy = {}; imageCopy.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageCopy.srcSubresource.layerCount = 1; @@ -499,7 +500,7 @@ void Renderer::takeScreenshot(RenderTarget* target) { imageCopy.extent.width = target->extent.width; imageCopy.extent.height = target->extent.height; imageCopy.extent.depth = 1; - + // Issue the copy command vkCmdCopyImage( commandBuffer, @@ -509,7 +510,7 @@ void Renderer::takeScreenshot(RenderTarget* target) { VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &imageCopy); - + // change screenshot image from transfer dst to general (for mapping memory) { VkImageMemoryBarrier imageMemoryBarrier = {}; @@ -522,7 +523,7 @@ void Renderer::takeScreenshot(RenderTarget* target) { imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageMemoryBarrier.subresourceRange.layerCount = 1; imageMemoryBarrier.subresourceRange.levelCount = 1; - + vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, @@ -532,7 +533,7 @@ void Renderer::takeScreenshot(RenderTarget* target) { 0, nullptr, 1, &imageMemoryBarrier); } - + // change offscreen image layout back to normal { VkImageMemoryBarrier imageMemoryBarrier = {}; @@ -545,7 +546,7 @@ void Renderer::takeScreenshot(RenderTarget* target) { imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageMemoryBarrier.subresourceRange.layerCount = 1; imageMemoryBarrier.subresourceRange.levelCount = 1; - + vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, @@ -555,54 +556,54 @@ void Renderer::takeScreenshot(RenderTarget* target) { 0, nullptr, 1, &imageMemoryBarrier); } - + vkEndCommandBuffer(commandBuffer); - + VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &commandBuffer; - + VkFenceCreateInfo fenceCreateInfo = {}; fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - + VkFence fence = nullptr; vkCreateFence(device_, &fenceCreateInfo, nullptr, &fence); - + vkQueueSubmit(graphicsQueue_, 1, &submitInfo, fence); - + vkWaitForFences(device_, 1, &fence, true, -1); vkDestroyFence(device_, fence, nullptr); - + vkFreeCommandBuffers(device_, commandPool_, 1, &commandBuffer); - + VkImageSubresource subResource = {}; subResource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - + VkSubresourceLayout subResourceLayout = {}; vkGetImageSubresourceLayout(device_, image, &subResource, &subResourceLayout); - + const char* data = nullptr; vkMapMemory(device_, imageMemory, 0, VK_WHOLE_SIZE, 0, (void**)&data); data += subResourceLayout.offset; - + std::ofstream file("screenshot.ppm", std::ios::out | std::ios::binary); file << "P6\n" << target->extent.width << "\n" << target->extent.height << "\n" << 255 << "\n"; - + for(uint32_t y = 0; y < target->extent.height; y++) { const unsigned int* row = reinterpret_cast(data); for(uint32_t x = 0; x < target->extent.width; x++) { file.write(reinterpret_cast(row), 3); row++; } - + data += subResourceLayout.rowPitch; } - + file.close(); - + vkUnmapMemory(device_, imageMemory); - + vkFreeMemory(device_, imageMemory, nullptr); vkDestroyImage(device_, image, nullptr); } diff --git a/src/worldpass.cpp b/src/worldpass.cpp index c83dd6e..2696074 100644 --- a/src/worldpass.cpp +++ b/src/worldpass.cpp @@ -7,6 +7,7 @@ #include "world.h" #include "mesh.h" #include "light.h" +#include "camera.h" WorldPass::WorldPass(Renderer& renderer) : renderer_(renderer) { createRenderPass(); @@ -28,7 +29,7 @@ WorldPass::~WorldPass() { vkDestroyBuffer(renderer_.getDevice(), lightBuffer_, nullptr); } -void WorldPass::render(VkCommandBuffer commandBuffer, World& world, RenderTarget* target) { +void WorldPass::render(VkCommandBuffer commandBuffer, World& world, Camera& camera, RenderTarget* target) { struct ShaderLight { glm::vec4 position; glm::vec3 color; @@ -65,7 +66,7 @@ void WorldPass::render(VkCommandBuffer commandBuffer, World& world, RenderTarget for(const auto& mesh : world.meshes) { glm::mat4 mvp; mvp = glm::perspective(glm::radians(75.0f), (float)target->extent.width / target->extent.height, 0.1f, 100.0f); - mvp *= glm::lookAt(glm::vec3(2), glm::vec3(0), glm::vec3(0, -1, 0)); + mvp *= glm::lookAt(camera.position, camera.target, glm::vec3(0, -1, 0)); vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &mvp);