Add moving camera
This commit is contained in:
parent
82ede190a6
commit
dd8131a059
6 changed files with 82 additions and 63 deletions
8
include/camera.h
Normal file
8
include/camera.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class Camera {
|
||||
public:
|
||||
glm::vec3 position, target;
|
||||
};
|
|
@ -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);
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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;
|
||||
|
|
101
src/renderer.cpp
101
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<const unsigned int*>(data);
|
||||
for(uint32_t x = 0; x < target->extent.width; x++) {
|
||||
file.write(reinterpret_cast<const char*>(row), 3);
|
||||
row++;
|
||||
}
|
||||
|
||||
|
||||
data += subResourceLayout.rowPitch;
|
||||
}
|
||||
|
||||
|
||||
file.close();
|
||||
|
||||
|
||||
vkUnmapMemory(device_, imageMemory);
|
||||
|
||||
|
||||
vkFreeMemory(device_, imageMemory, nullptr);
|
||||
vkDestroyImage(device_, image, nullptr);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Reference in a new issue