From 2b65968452f732e0de6382caafc14d9673ab0c01 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Tue, 25 Dec 2018 10:57:12 -0500 Subject: [PATCH] Add visual selection feedback --- CMakeLists.txt | 7 +- include/debugpass.h | 32 +++++ include/rendercollection.h | 6 +- include/renderer.h | 18 ++- shaders/post.frag | 27 ++++ shaders/sobel.frag | 7 + shaders/sobel.vert | 12 ++ src/debugpass.cpp | 197 ++++++++++++++++++++++++++++ src/postpass.cpp | 44 ++++++- src/renderer.cpp | 72 +++++++++- tools/common/include/context.h | 4 + tools/common/src/renderwindow.cpp | 6 +- tools/leveleditor/src/hierarchy.cpp | 10 ++ 13 files changed, 432 insertions(+), 10 deletions(-) create mode 100644 include/debugpass.h create mode 100755 shaders/sobel.frag create mode 100755 shaders/sobel.vert create mode 100644 src/debugpass.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b86aa5..4e2654a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,7 +57,8 @@ set(ENGINE_SRC src/worldmanager.cpp src/assetmanager.cpp src/entityparser.cpp - src/smaapass.cpp) + src/smaapass.cpp + src/debugpass.cpp) if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(ENGINE_SRC @@ -112,7 +113,9 @@ add_shaders(Graph shaders/edge.vert shaders/edge.frag shaders/blend.vert - shaders/blend.frag) + shaders/blend.frag + shaders/sobel.vert + shaders/sobel.frag) add_data(Graph data/suzanne.obj diff --git a/include/debugpass.h b/include/debugpass.h new file mode 100644 index 0000000..63912e4 --- /dev/null +++ b/include/debugpass.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +class Renderer; +struct RenderTarget; +struct RenderCollection; +struct RenderExtraInfo; + +class DebugPass { +public: + DebugPass(Renderer& renderer); + ~DebugPass(); + + void render(VkCommandBuffer commandBuffer, RenderCollection& collection, RenderExtraInfo* extraInfo, RenderTarget* target); + + VkRenderPass getRenderPass() const { + return renderPass_; + } + +private: + void createRenderPass(); + void createPipeline(); + + VkRenderPass renderPass_ = nullptr; + + VkPipeline pipeline_ = nullptr; + VkPipelineLayout pipelineLayout_ = nullptr; + + Renderer& renderer_; +}; diff --git a/include/rendercollection.h b/include/rendercollection.h index a664e59..50ad706 100644 --- a/include/rendercollection.h +++ b/include/rendercollection.h @@ -7,12 +7,16 @@ struct MeshComponent; struct LightComponent; struct CameraComponent; +using EntityID = uint64_t; + struct RenderLight { TransformComponent* transform = nullptr; LightComponent* light = nullptr; }; struct RenderMesh { + EntityID entity; + TransformComponent* transform = nullptr; MeshComponent* mesh = nullptr; }; @@ -25,6 +29,6 @@ struct RenderCamera { struct RenderCollection { std::vector lights; std::vector meshes; - + RenderCamera camera; }; diff --git a/include/renderer.h b/include/renderer.h index 0c6e457..128f99d 100644 --- a/include/renderer.h +++ b/include/renderer.h @@ -9,6 +9,7 @@ #include "skypass.h" #include "shadowpass.h" #include "smaapass.h" +#include "debugpass.h" constexpr int numFrameResources = 2; @@ -36,6 +37,13 @@ struct RenderTarget { VkFramebuffer* offscreenFramebuffers = nullptr; + // sobel + VkImage* sobelImages = nullptr; + VkDeviceMemory* sobelMemorys = nullptr; + VkImageView* sobelImageViews = nullptr; + + VkFramebuffer* sobelFramebuffers = nullptr; + // near field VkImage* nearFieldImages = nullptr; VkDeviceMemory* nearFieldMemory = nullptr; @@ -90,6 +98,13 @@ struct GraphicsConfig { #endif }; +using EntityID = uint64_t; + +struct RenderExtraInfo { + EntityID* selectedEntities = nullptr; + size_t numSelectedEntities = 0; +}; + struct World; class MeshAsset; class Camera; @@ -100,7 +115,7 @@ public: Renderer(GraphicsConfig config); ~Renderer(); - void render(World& world, RenderTarget* target); + void render(World& world, RenderTarget* target, RenderExtraInfo* extraInfo = nullptr); RenderTarget* createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTarget* oldTarget = nullptr); void destroyRenderTarget(RenderTarget* target); @@ -219,4 +234,5 @@ private: SkyPass* skyPass_ = nullptr; ShadowPass* shadowPass_ = nullptr; SMAAPass* smaaPass_ = nullptr; + DebugPass* debugPass_ = nullptr; }; diff --git a/shaders/post.frag b/shaders/post.frag index 33ea1fb..4bff892 100644 --- a/shaders/post.frag +++ b/shaders/post.frag @@ -22,6 +22,11 @@ layout(binding = 1) uniform sampler2D depthSampler; layout(binding = 2) uniform sampler2D nearFieldSampler; layout(binding = 3) uniform sampler2D farFieldSampler; layout(binding = 4) uniform sampler2D blendSampler; +layout(binding = 5) uniform sampler2D sobelSampler; + +layout(push_constant) uniform PushConstants { + vec4 viewport; +} pushConstants; void main() { vec3 sceneColor = vec3(0); @@ -43,5 +48,27 @@ void main() { //float coc2 = texture(nearFieldSampler, inUV).a; //vec3 finalColor = mix(farColorBlurred, nearColor, clamp(clamp(-coc2 - 1.0, 0.0, 1.0) + texture(nearFieldSampler, inUV).a * 8.0, 0.0, 1.0)); + float thickness = 3.0; + float thicknessX = thickness * pushConstants.viewport.x * (pushConstants.viewport.z / 1920.0); + float thicknessY = thickness * pushConstants.viewport.y * (pushConstants.viewport.w / 1080.0); + + vec4 top = texture(sobelSampler, vec2(inUV.x, inUV.y + thicknessY)); + vec4 bottom = texture(sobelSampler, vec2(inUV.x, inUV.y - thicknessY)); + vec4 left = texture(sobelSampler, vec2(inUV.x - thicknessX, inUV.y)); + vec4 right = texture(sobelSampler, vec2(inUV.x + thicknessX, inUV.y)); + vec4 topLeft = texture(sobelSampler, vec2(inUV.x - thicknessX, inUV.y + thicknessY)); + vec4 topRight = texture(sobelSampler, vec2(inUV.x + thicknessX, inUV.y + thicknessY)); + vec4 bottomLeft = texture(sobelSampler, vec2(inUV.x - thicknessX, inUV.y - thicknessY)); + vec4 bottomRight = texture(sobelSampler, vec2(inUV.x + thicknessX, inUV.y - thicknessY)); + + vec4 sx = -topLeft - 2 * left - bottomLeft + topRight + 2 * right + bottomRight; + vec4 sy = -topLeft - 2 * top - topRight + bottomLeft + 2 * bottom + bottomRight; + vec4 sobel = sqrt(sx * sx + sy * sy); + sobel = clamp(sobel / 5.0, 0.0, 1.0); + + vec4 outlineColor = vec4(0.1, 0.5, 0.9, 1.0); + outColor = vec4(farColorBlurred, 1.0); + outColor = outlineColor*sobel + outColor*(1.0 - sobel); + outColor += outlineColor * texture(sobelSampler, inUV) * 0.3; } diff --git a/shaders/sobel.frag b/shaders/sobel.frag new file mode 100755 index 0000000..321bcf4 --- /dev/null +++ b/shaders/sobel.frag @@ -0,0 +1,7 @@ +#version 450 core + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(1.0); +} diff --git a/shaders/sobel.vert b/shaders/sobel.vert new file mode 100755 index 0000000..ec200f2 --- /dev/null +++ b/shaders/sobel.vert @@ -0,0 +1,12 @@ +#version 450 core + +layout(location = 0) in vec3 inPosition; + +layout(push_constant) uniform PushConsts { + mat4 mvp; +} pushConstants; + +void main() { + gl_Position = pushConstants.mvp * vec4(inPosition, 1.0); +} + diff --git a/src/debugpass.cpp b/src/debugpass.cpp new file mode 100644 index 0000000..66eb46b --- /dev/null +++ b/src/debugpass.cpp @@ -0,0 +1,197 @@ +#include "debugpass.h" + +#include + +#include "rendercollection.h" +#include "renderer.h" +#include "ecs.h" +#include "mesh.h" + +DebugPass::DebugPass(Renderer& renderer) : renderer_(renderer) { + createRenderPass(); + createPipeline(); +} + +DebugPass::~DebugPass() { +} + +void DebugPass::render(VkCommandBuffer commandBuffer, RenderCollection& collection, RenderExtraInfo* extraInfo, RenderTarget* target) { + VkClearValue clearValue = {}; + clearValue.color = {0.0f, 0.0f, 0.0f, 0.0f}; + + VkRenderPassBeginInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = renderPass_; + renderPassInfo.framebuffer = target->sobelFramebuffers[target->currentResource]; + renderPassInfo.renderArea.extent = target->extent; + renderPassInfo.clearValueCount = 1; + renderPassInfo.pClearValues = &clearValue; + + vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_); + + for(auto mesh : collection.meshes) { + bool shouldRender = false; + for(int i = 0; i < extraInfo->numSelectedEntities; i++) { + if(extraInfo->selectedEntities[i] == mesh.entity) + shouldRender = true; + } + + if(shouldRender) { + glm::mat4 mvp; + mvp = glm::perspective(glm::radians(collection.camera.camera->fov), (float)target->extent.width / target->extent.height, collection.camera.camera->near, collection.camera.camera->far); + mvp *= glm::lookAt(collection.camera.transform->position, collection.camera.camera->target, glm::vec3(0, -1, 0)); + mvp = glm::translate(mvp, mesh.transform->position); + + vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &mvp); + + const VkDeviceSize offsets[] = {0}; + vkCmdBindVertexBuffers(commandBuffer, 0, 1, &mesh.mesh->mesh->vertexBuffer, offsets); + vkCmdBindIndexBuffer(commandBuffer, mesh.mesh->mesh->indexBuffer, 0, VK_INDEX_TYPE_UINT32); + + vkCmdDrawIndexed(commandBuffer, mesh.mesh->mesh->indices.size(), 1, 0, 0, 0); + } + } + + vkCmdEndRenderPass(commandBuffer); +} + +void DebugPass::createRenderPass() { + VkAttachmentDescription colorAttachment = {}; + colorAttachment.format = VK_FORMAT_R16G16B16A16_SFLOAT; + colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + colorAttachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + VkAttachmentReference colorAttachmentRef = {}; + colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorAttachmentRef; + + VkSubpassDependency dependency = {}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.srcAccessMask = 0; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + + VkRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.attachmentCount = 1; + renderPassInfo.pAttachments = &colorAttachment; + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = &subpass; + renderPassInfo.dependencyCount = 1; + renderPassInfo.pDependencies = &dependency; + + vkCreateRenderPass(renderer_.getDevice(), &renderPassInfo, nullptr, &renderPass_); +} + +void DebugPass::createPipeline() { + VkShaderModule vertShaderModule = renderer_.createShader("shaders/sobel.vert.spv"); + VkShaderModule fragShaderModule = renderer_.createShader("shaders/sobel.frag.spv"); + + VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; + vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; + vertShaderStageInfo.module = vertShaderModule; + vertShaderStageInfo.pName = "main"; + + VkPipelineShaderStageCreateInfo fragShaderStageInfo = {}; + fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + fragShaderStageInfo.module = fragShaderModule; + fragShaderStageInfo.pName = "main"; + + const std::array shaderStages = {vertShaderStageInfo, fragShaderStageInfo}; + + VkVertexInputBindingDescription vertexBindingDescription = {}; + vertexBindingDescription.stride = sizeof(Vertex); + + VkVertexInputAttributeDescription positionAttributeDescription = {}; + positionAttributeDescription.format = VK_FORMAT_R32G32B32_SFLOAT; + + VkPipelineVertexInputStateCreateInfo vertexInputInfo = {}; + vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputInfo.vertexBindingDescriptionCount = 1; + vertexInputInfo.pVertexBindingDescriptions = &vertexBindingDescription; + vertexInputInfo.vertexAttributeDescriptionCount = 1; + vertexInputInfo.pVertexAttributeDescriptions = &positionAttributeDescription; + + VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; + inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + VkPipelineViewportStateCreateInfo viewportState = {}; + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportState.viewportCount = 1; + viewportState.scissorCount = 1; + + VkPipelineRasterizationStateCreateInfo rasterizer = {}; + rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.cullMode = VK_CULL_MODE_NONE; + rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizer.lineWidth = 1.0f; + + VkPipelineMultisampleStateCreateInfo multisampling = {}; + multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; + colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo colorBlending = {}; + colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlending.attachmentCount = 1; + colorBlending.pAttachments = &colorBlendAttachment; + + const std::array dynamicStates = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR + }; + + VkPipelineDynamicStateCreateInfo dynamicState = {}; + dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicState.dynamicStateCount = dynamicStates.size(); + dynamicState.pDynamicStates = dynamicStates.data(); + + VkPushConstantRange pushConstant = {}; + pushConstant.size = sizeof(glm::mat4); + pushConstant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.pushConstantRangeCount = 1; + pipelineLayoutInfo.pPushConstantRanges = &pushConstant; + + vkCreatePipelineLayout(renderer_.getDevice(), &pipelineLayoutInfo, nullptr, &pipelineLayout_); + + VkGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineInfo.stageCount = shaderStages.size(); + pipelineInfo.pStages = shaderStages.data(); + pipelineInfo.pVertexInputState = &vertexInputInfo; + pipelineInfo.pInputAssemblyState = &inputAssembly; + pipelineInfo.pViewportState = &viewportState; + pipelineInfo.pRasterizationState = &rasterizer; + pipelineInfo.pMultisampleState = &multisampling; + pipelineInfo.pColorBlendState = &colorBlending; + pipelineInfo.pDynamicState = &dynamicState; + pipelineInfo.layout = pipelineLayout_; + pipelineInfo.renderPass = renderPass_; + + vkCreateGraphicsPipelines(renderer_.getDevice(), nullptr, 1, &pipelineInfo, nullptr, &pipeline_); + + vkDestroyShaderModule(renderer_.getDevice(), fragShaderModule, nullptr); + vkDestroyShaderModule(renderer_.getDevice(), vertShaderModule, nullptr); +} diff --git a/src/postpass.cpp b/src/postpass.cpp index 48770ec..c2dd0e2 100644 --- a/src/postpass.cpp +++ b/src/postpass.cpp @@ -22,6 +22,15 @@ PostPass::~PostPass() { void PostPass::render(VkCommandBuffer commandBuffer, RenderTarget* target) { vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_); vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &target->postSets[target->currentResource], 0, nullptr); + + glm::vec4 viewport; + viewport.x = 1.0 / target->extent.width; + viewport.y = 1.0 / target->extent.height; + viewport.z = target->extent.width; + viewport.w = target->extent.height; + + vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(glm::vec4), &viewport); + vkCmdDraw(commandBuffer, 3, 1, 0, 0); } @@ -69,6 +78,11 @@ void PostPass::createDescriptorSet(RenderTarget* target) { blendImageInfo.imageView = target->blendImageViews[i]; blendImageInfo.sampler = offscreenSampler_; + VkDescriptorImageInfo sobelImageInfo = {}; + sobelImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + sobelImageInfo.imageView = target->sobelImageViews[i]; + sobelImageInfo.sampler = offscreenSampler_; + VkWriteDescriptorSet sceneDescriptorWrite = {}; sceneDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; sceneDescriptorWrite.descriptorCount = 1; @@ -108,12 +122,21 @@ void PostPass::createDescriptorSet(RenderTarget* target) { blendDescriptorWrite.dstSet = target->postSets[i]; blendDescriptorWrite.pImageInfo = &blendImageInfo; - const std::array descriptorWrites = { + VkWriteDescriptorSet sobelDescriptorWrite = {}; + sobelDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + sobelDescriptorWrite.descriptorCount = 1; + sobelDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + sobelDescriptorWrite.dstBinding = 5; + sobelDescriptorWrite.dstSet = target->postSets[i]; + sobelDescriptorWrite.pImageInfo = &sobelImageInfo; + + const std::array descriptorWrites = { sceneDescriptorWrite, depthDescriptorWrite, nearFieldDescriptorWrite, farFieldDescriptorWrite, - blendDescriptorWrite + blendDescriptorWrite, + sobelDescriptorWrite }; vkUpdateDescriptorSets(renderer_.getDevice(), descriptorWrites.size(), descriptorWrites.data(), 0, nullptr); @@ -150,12 +173,19 @@ void PostPass::createDescriptorSetLayout() { blendSamplerBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; blendSamplerBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - const std::array bindings = { + VkDescriptorSetLayoutBinding sobelSamplerBinding = {}; + sobelSamplerBinding.binding = 5; + sobelSamplerBinding.descriptorCount = 1; + sobelSamplerBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + sobelSamplerBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + + const std::array bindings = { offscreenSamplerBinding, depthSamplerBinding, nearFieldSamplerBinding, farFieldSamplerBinding, - blendSamplerBinding + blendSamplerBinding, + sobelSamplerBinding }; VkDescriptorSetLayoutCreateInfo createInfo = {}; @@ -226,10 +256,16 @@ void PostPass::createPipeline() { dynamicState.dynamicStateCount = dynamicStates.size(); dynamicState.pDynamicStates = dynamicStates.data(); + VkPushConstantRange pushConstant = {}; + pushConstant.size = sizeof(glm::vec4); + pushConstant.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = 1; pipelineLayoutInfo.pSetLayouts = &setLayout_; + pipelineLayoutInfo.pushConstantRangeCount = 1; + pipelineLayoutInfo.pPushConstantRanges = &pushConstant; vkCreatePipelineLayout(renderer_.getDevice(), &pipelineLayoutInfo, nullptr, &pipelineLayout_); diff --git a/src/renderer.cpp b/src/renderer.cpp index 36c69ce..c6c8e0d 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -39,11 +39,13 @@ Renderer::Renderer(GraphicsConfig config) : config_(config) { #endif skyPass_ = new SkyPass(*this); smaaPass_ = new SMAAPass(*this); + debugPass_ = new DebugPass(*this); } Renderer::~Renderer() { vkDeviceWaitIdle(device_); + delete debugPass_; delete smaaPass_; delete skyPass_; #ifdef DEBUG @@ -72,7 +74,7 @@ Renderer::~Renderer() { vkDestroyInstance(instance_, nullptr); } -void Renderer::render(World& world, RenderTarget* target) { +void Renderer::render(World& world, RenderTarget* target, RenderExtraInfo* extraInfo) { RenderCollection collection; // generate collection @@ -80,6 +82,7 @@ void Renderer::render(World& world, RenderTarget* target) { auto meshes = ECS::getWorldComponents(&world); for(auto [id, mesh] : meshes) { RenderMesh renderMesh; + renderMesh.entity = id; renderMesh.mesh = mesh; renderMesh.transform = ECS::getComponent(id); @@ -149,6 +152,9 @@ void Renderer::render(World& world, RenderTarget* target) { vkCmdEndRenderPass(commandBuffer); + if(extraInfo) + debugPass_->render(commandBuffer, collection, extraInfo, target); + dofPass_->render(commandBuffer, *collection.camera.camera, target); // reset after dof pass @@ -308,6 +314,13 @@ RenderTarget* Renderer::createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTa target->offscreenFramebuffers = new VkFramebuffer[numFrameResources]; + // sobel + target->sobelImages = new VkImage[numFrameResources]; + target->sobelMemorys = new VkDeviceMemory[numFrameResources]; + target->sobelImageViews = new VkImageView[numFrameResources]; + + target->sobelFramebuffers = new VkFramebuffer[numFrameResources]; + // dof target->nearFieldImages = new VkImage[numFrameResources]; target->nearFieldMemory = new VkDeviceMemory[numFrameResources]; @@ -446,6 +459,63 @@ RenderTarget* Renderer::createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTa vkCreateFramebuffer(device_, &framebufferInfo, nullptr, &target->offscreenFramebuffers[i]); } + // sobel image + { + VkImageCreateInfo imageCreateInfo = {}; + imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; + imageCreateInfo.format = VK_FORMAT_R16G16B16A16_SFLOAT; + imageCreateInfo.extent.width = target->extent.width; + imageCreateInfo.extent.height = target->extent.height; + imageCreateInfo.extent.depth = 1; + imageCreateInfo.mipLevels = 1; + imageCreateInfo.arrayLayers = 1; + imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCreateInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + + vkCreateImage(device_, &imageCreateInfo, nullptr, &target->sobelImages[i]); + + VkMemoryRequirements memoryRequirements = {}; + vkGetImageMemoryRequirements(device_, target->sobelImages[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->sobelMemorys[i]); + vkBindImageMemory(device_, target->sobelImages[i], target->sobelMemorys[i], 0); + } + + // sobel image view + { + VkImageViewCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = target->sobelImages[i]; + createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + createInfo.format = VK_FORMAT_R16G16B16A16_SFLOAT; + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + createInfo.subresourceRange.levelCount = 1; + createInfo.subresourceRange.layerCount = 1; + + vkCreateImageView(device_, &createInfo, nullptr, &target->sobelImageViews[i]); + } + + // sobel framebuffer + { + VkFramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = debugPass_->getRenderPass(); + framebufferInfo.attachmentCount = 1; + framebufferInfo.pAttachments = &target->sobelImageViews[i]; + framebufferInfo.width = target->extent.width; + framebufferInfo.height = target->extent.height; + framebufferInfo.layers = 1; + + vkCreateFramebuffer(device_, &framebufferInfo, nullptr, &target->sobelFramebuffers[i]); + } + // near field color { VkImageCreateInfo imageCreateInfo = {}; diff --git a/tools/common/include/context.h b/tools/common/include/context.h index bcf5a29..6ac2eb4 100644 --- a/tools/common/include/context.h +++ b/tools/common/include/context.h @@ -2,6 +2,10 @@ class Renderer; +using EntityID = uint64_t; + struct Context { Renderer* renderer; + + std::vector selectedEntities; }; diff --git a/tools/common/src/renderwindow.cpp b/tools/common/src/renderwindow.cpp index c9576ab..6f2bb69 100644 --- a/tools/common/src/renderwindow.cpp +++ b/tools/common/src/renderwindow.cpp @@ -50,7 +50,11 @@ void RendererWindow::render() { if(target->extent.width != width || target->extent.height != height) target = context.renderer->createSurfaceRenderTarget(surface, target); - context.renderer->render(*worldManager.getCurrentWorld(), target); + RenderExtraInfo extraInfo; + extraInfo.selectedEntities = context.selectedEntities.data(); + extraInfo.numSelectedEntities = context.selectedEntities.size(); + + context.renderer->render(*worldManager.getCurrentWorld(), target, &extraInfo); vulkanInstance()->presentQueued(this); requestUpdate(); diff --git a/tools/leveleditor/src/hierarchy.cpp b/tools/leveleditor/src/hierarchy.cpp index e6808b0..69dc18d 100644 --- a/tools/leveleditor/src/hierarchy.cpp +++ b/tools/leveleditor/src/hierarchy.cpp @@ -15,6 +15,16 @@ Hierarchy::Hierarchy(Context& context, QWidget* parent) : QWidget(parent), conte listView = new QListView(); layout->addWidget(listView); + connect(listView, &QListView::clicked, [&context](QModelIndex index) { + context.selectedEntities.clear(); + + if(index.isValid()) { + const auto entity = ECS::getWorldEntities(worldManager.getCurrentWorld())[index.row()]; + + context.selectedEntities.push_back(entity); + } + }); + listModel = new QStringListModel(); listView->setModel(listModel);