Add visual selection feedback
This commit is contained in:
parent
462462331a
commit
2b65968452
13 changed files with 432 additions and 10 deletions
|
@ -57,7 +57,8 @@ set(ENGINE_SRC
|
||||||
src/worldmanager.cpp
|
src/worldmanager.cpp
|
||||||
src/assetmanager.cpp
|
src/assetmanager.cpp
|
||||||
src/entityparser.cpp
|
src/entityparser.cpp
|
||||||
src/smaapass.cpp)
|
src/smaapass.cpp
|
||||||
|
src/debugpass.cpp)
|
||||||
|
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
set(ENGINE_SRC
|
set(ENGINE_SRC
|
||||||
|
@ -112,7 +113,9 @@ add_shaders(Graph
|
||||||
shaders/edge.vert
|
shaders/edge.vert
|
||||||
shaders/edge.frag
|
shaders/edge.frag
|
||||||
shaders/blend.vert
|
shaders/blend.vert
|
||||||
shaders/blend.frag)
|
shaders/blend.frag
|
||||||
|
shaders/sobel.vert
|
||||||
|
shaders/sobel.frag)
|
||||||
|
|
||||||
add_data(Graph
|
add_data(Graph
|
||||||
data/suzanne.obj
|
data/suzanne.obj
|
||||||
|
|
32
include/debugpass.h
Normal file
32
include/debugpass.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
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_;
|
||||||
|
};
|
|
@ -7,12 +7,16 @@ struct MeshComponent;
|
||||||
struct LightComponent;
|
struct LightComponent;
|
||||||
struct CameraComponent;
|
struct CameraComponent;
|
||||||
|
|
||||||
|
using EntityID = uint64_t;
|
||||||
|
|
||||||
struct RenderLight {
|
struct RenderLight {
|
||||||
TransformComponent* transform = nullptr;
|
TransformComponent* transform = nullptr;
|
||||||
LightComponent* light = nullptr;
|
LightComponent* light = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RenderMesh {
|
struct RenderMesh {
|
||||||
|
EntityID entity;
|
||||||
|
|
||||||
TransformComponent* transform = nullptr;
|
TransformComponent* transform = nullptr;
|
||||||
MeshComponent* mesh = nullptr;
|
MeshComponent* mesh = nullptr;
|
||||||
};
|
};
|
||||||
|
@ -25,6 +29,6 @@ struct RenderCamera {
|
||||||
struct RenderCollection {
|
struct RenderCollection {
|
||||||
std::vector<RenderLight> lights;
|
std::vector<RenderLight> lights;
|
||||||
std::vector<RenderMesh> meshes;
|
std::vector<RenderMesh> meshes;
|
||||||
|
|
||||||
RenderCamera camera;
|
RenderCamera camera;
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "skypass.h"
|
#include "skypass.h"
|
||||||
#include "shadowpass.h"
|
#include "shadowpass.h"
|
||||||
#include "smaapass.h"
|
#include "smaapass.h"
|
||||||
|
#include "debugpass.h"
|
||||||
|
|
||||||
constexpr int numFrameResources = 2;
|
constexpr int numFrameResources = 2;
|
||||||
|
|
||||||
|
@ -36,6 +37,13 @@ struct RenderTarget {
|
||||||
|
|
||||||
VkFramebuffer* offscreenFramebuffers = nullptr;
|
VkFramebuffer* offscreenFramebuffers = nullptr;
|
||||||
|
|
||||||
|
// sobel
|
||||||
|
VkImage* sobelImages = nullptr;
|
||||||
|
VkDeviceMemory* sobelMemorys = nullptr;
|
||||||
|
VkImageView* sobelImageViews = nullptr;
|
||||||
|
|
||||||
|
VkFramebuffer* sobelFramebuffers = nullptr;
|
||||||
|
|
||||||
// near field
|
// near field
|
||||||
VkImage* nearFieldImages = nullptr;
|
VkImage* nearFieldImages = nullptr;
|
||||||
VkDeviceMemory* nearFieldMemory = nullptr;
|
VkDeviceMemory* nearFieldMemory = nullptr;
|
||||||
|
@ -90,6 +98,13 @@ struct GraphicsConfig {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using EntityID = uint64_t;
|
||||||
|
|
||||||
|
struct RenderExtraInfo {
|
||||||
|
EntityID* selectedEntities = nullptr;
|
||||||
|
size_t numSelectedEntities = 0;
|
||||||
|
};
|
||||||
|
|
||||||
struct World;
|
struct World;
|
||||||
class MeshAsset;
|
class MeshAsset;
|
||||||
class Camera;
|
class Camera;
|
||||||
|
@ -100,7 +115,7 @@ public:
|
||||||
Renderer(GraphicsConfig config);
|
Renderer(GraphicsConfig config);
|
||||||
~Renderer();
|
~Renderer();
|
||||||
|
|
||||||
void render(World& world, RenderTarget* target);
|
void render(World& world, RenderTarget* target, RenderExtraInfo* extraInfo = nullptr);
|
||||||
|
|
||||||
RenderTarget* createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTarget* oldTarget = nullptr);
|
RenderTarget* createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTarget* oldTarget = nullptr);
|
||||||
void destroyRenderTarget(RenderTarget* target);
|
void destroyRenderTarget(RenderTarget* target);
|
||||||
|
@ -219,4 +234,5 @@ private:
|
||||||
SkyPass* skyPass_ = nullptr;
|
SkyPass* skyPass_ = nullptr;
|
||||||
ShadowPass* shadowPass_ = nullptr;
|
ShadowPass* shadowPass_ = nullptr;
|
||||||
SMAAPass* smaaPass_ = nullptr;
|
SMAAPass* smaaPass_ = nullptr;
|
||||||
|
DebugPass* debugPass_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,6 +22,11 @@ layout(binding = 1) uniform sampler2D depthSampler;
|
||||||
layout(binding = 2) uniform sampler2D nearFieldSampler;
|
layout(binding = 2) uniform sampler2D nearFieldSampler;
|
||||||
layout(binding = 3) uniform sampler2D farFieldSampler;
|
layout(binding = 3) uniform sampler2D farFieldSampler;
|
||||||
layout(binding = 4) uniform sampler2D blendSampler;
|
layout(binding = 4) uniform sampler2D blendSampler;
|
||||||
|
layout(binding = 5) uniform sampler2D sobelSampler;
|
||||||
|
|
||||||
|
layout(push_constant) uniform PushConstants {
|
||||||
|
vec4 viewport;
|
||||||
|
} pushConstants;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec3 sceneColor = vec3(0);
|
vec3 sceneColor = vec3(0);
|
||||||
|
@ -43,5 +48,27 @@ void main() {
|
||||||
//float coc2 = texture(nearFieldSampler, inUV).a;
|
//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));
|
//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 = vec4(farColorBlurred, 1.0);
|
||||||
|
outColor = outlineColor*sobel + outColor*(1.0 - sobel);
|
||||||
|
outColor += outlineColor * texture(sobelSampler, inUV) * 0.3;
|
||||||
}
|
}
|
||||||
|
|
7
shaders/sobel.frag
Executable file
7
shaders/sobel.frag
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#version 450 core
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
outColor = vec4(1.0);
|
||||||
|
}
|
12
shaders/sobel.vert
Executable file
12
shaders/sobel.vert
Executable file
|
@ -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);
|
||||||
|
}
|
||||||
|
|
197
src/debugpass.cpp
Normal file
197
src/debugpass.cpp
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
#include "debugpass.h"
|
||||||
|
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
|
#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<VkPipelineShaderStageCreateInfo, 2> 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<VkDynamicState, 2> 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);
|
||||||
|
}
|
|
@ -22,6 +22,15 @@ PostPass::~PostPass() {
|
||||||
void PostPass::render(VkCommandBuffer commandBuffer, RenderTarget* target) {
|
void PostPass::render(VkCommandBuffer commandBuffer, RenderTarget* target) {
|
||||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_);
|
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_);
|
||||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &target->postSets[target->currentResource], 0, nullptr);
|
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);
|
vkCmdDraw(commandBuffer, 3, 1, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +78,11 @@ void PostPass::createDescriptorSet(RenderTarget* target) {
|
||||||
blendImageInfo.imageView = target->blendImageViews[i];
|
blendImageInfo.imageView = target->blendImageViews[i];
|
||||||
blendImageInfo.sampler = offscreenSampler_;
|
blendImageInfo.sampler = offscreenSampler_;
|
||||||
|
|
||||||
|
VkDescriptorImageInfo sobelImageInfo = {};
|
||||||
|
sobelImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
sobelImageInfo.imageView = target->sobelImageViews[i];
|
||||||
|
sobelImageInfo.sampler = offscreenSampler_;
|
||||||
|
|
||||||
VkWriteDescriptorSet sceneDescriptorWrite = {};
|
VkWriteDescriptorSet sceneDescriptorWrite = {};
|
||||||
sceneDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
sceneDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
sceneDescriptorWrite.descriptorCount = 1;
|
sceneDescriptorWrite.descriptorCount = 1;
|
||||||
|
@ -108,12 +122,21 @@ void PostPass::createDescriptorSet(RenderTarget* target) {
|
||||||
blendDescriptorWrite.dstSet = target->postSets[i];
|
blendDescriptorWrite.dstSet = target->postSets[i];
|
||||||
blendDescriptorWrite.pImageInfo = &blendImageInfo;
|
blendDescriptorWrite.pImageInfo = &blendImageInfo;
|
||||||
|
|
||||||
const std::array<VkWriteDescriptorSet, 5> 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<VkWriteDescriptorSet, 6> descriptorWrites = {
|
||||||
sceneDescriptorWrite,
|
sceneDescriptorWrite,
|
||||||
depthDescriptorWrite,
|
depthDescriptorWrite,
|
||||||
nearFieldDescriptorWrite,
|
nearFieldDescriptorWrite,
|
||||||
farFieldDescriptorWrite,
|
farFieldDescriptorWrite,
|
||||||
blendDescriptorWrite
|
blendDescriptorWrite,
|
||||||
|
sobelDescriptorWrite
|
||||||
};
|
};
|
||||||
|
|
||||||
vkUpdateDescriptorSets(renderer_.getDevice(), descriptorWrites.size(), descriptorWrites.data(), 0, nullptr);
|
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.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
blendSamplerBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
blendSamplerBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
|
||||||
const std::array<VkDescriptorSetLayoutBinding, 5> 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<VkDescriptorSetLayoutBinding, 6> bindings = {
|
||||||
offscreenSamplerBinding,
|
offscreenSamplerBinding,
|
||||||
depthSamplerBinding,
|
depthSamplerBinding,
|
||||||
nearFieldSamplerBinding,
|
nearFieldSamplerBinding,
|
||||||
farFieldSamplerBinding,
|
farFieldSamplerBinding,
|
||||||
blendSamplerBinding
|
blendSamplerBinding,
|
||||||
|
sobelSamplerBinding
|
||||||
};
|
};
|
||||||
|
|
||||||
VkDescriptorSetLayoutCreateInfo createInfo = {};
|
VkDescriptorSetLayoutCreateInfo createInfo = {};
|
||||||
|
@ -226,10 +256,16 @@ void PostPass::createPipeline() {
|
||||||
dynamicState.dynamicStateCount = dynamicStates.size();
|
dynamicState.dynamicStateCount = dynamicStates.size();
|
||||||
dynamicState.pDynamicStates = dynamicStates.data();
|
dynamicState.pDynamicStates = dynamicStates.data();
|
||||||
|
|
||||||
|
VkPushConstantRange pushConstant = {};
|
||||||
|
pushConstant.size = sizeof(glm::vec4);
|
||||||
|
pushConstant.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
|
||||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
|
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
|
||||||
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
pipelineLayoutInfo.setLayoutCount = 1;
|
pipelineLayoutInfo.setLayoutCount = 1;
|
||||||
pipelineLayoutInfo.pSetLayouts = &setLayout_;
|
pipelineLayoutInfo.pSetLayouts = &setLayout_;
|
||||||
|
pipelineLayoutInfo.pushConstantRangeCount = 1;
|
||||||
|
pipelineLayoutInfo.pPushConstantRanges = &pushConstant;
|
||||||
|
|
||||||
vkCreatePipelineLayout(renderer_.getDevice(), &pipelineLayoutInfo, nullptr, &pipelineLayout_);
|
vkCreatePipelineLayout(renderer_.getDevice(), &pipelineLayoutInfo, nullptr, &pipelineLayout_);
|
||||||
|
|
||||||
|
|
|
@ -39,11 +39,13 @@ Renderer::Renderer(GraphicsConfig config) : config_(config) {
|
||||||
#endif
|
#endif
|
||||||
skyPass_ = new SkyPass(*this);
|
skyPass_ = new SkyPass(*this);
|
||||||
smaaPass_ = new SMAAPass(*this);
|
smaaPass_ = new SMAAPass(*this);
|
||||||
|
debugPass_ = new DebugPass(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer::~Renderer() {
|
Renderer::~Renderer() {
|
||||||
vkDeviceWaitIdle(device_);
|
vkDeviceWaitIdle(device_);
|
||||||
|
|
||||||
|
delete debugPass_;
|
||||||
delete smaaPass_;
|
delete smaaPass_;
|
||||||
delete skyPass_;
|
delete skyPass_;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -72,7 +74,7 @@ Renderer::~Renderer() {
|
||||||
vkDestroyInstance(instance_, nullptr);
|
vkDestroyInstance(instance_, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::render(World& world, RenderTarget* target) {
|
void Renderer::render(World& world, RenderTarget* target, RenderExtraInfo* extraInfo) {
|
||||||
RenderCollection collection;
|
RenderCollection collection;
|
||||||
|
|
||||||
// generate collection
|
// generate collection
|
||||||
|
@ -80,6 +82,7 @@ void Renderer::render(World& world, RenderTarget* target) {
|
||||||
auto meshes = ECS::getWorldComponents<MeshComponent>(&world);
|
auto meshes = ECS::getWorldComponents<MeshComponent>(&world);
|
||||||
for(auto [id, mesh] : meshes) {
|
for(auto [id, mesh] : meshes) {
|
||||||
RenderMesh renderMesh;
|
RenderMesh renderMesh;
|
||||||
|
renderMesh.entity = id;
|
||||||
renderMesh.mesh = mesh;
|
renderMesh.mesh = mesh;
|
||||||
renderMesh.transform = ECS::getComponent<TransformComponent>(id);
|
renderMesh.transform = ECS::getComponent<TransformComponent>(id);
|
||||||
|
|
||||||
|
@ -149,6 +152,9 @@ void Renderer::render(World& world, RenderTarget* target) {
|
||||||
|
|
||||||
vkCmdEndRenderPass(commandBuffer);
|
vkCmdEndRenderPass(commandBuffer);
|
||||||
|
|
||||||
|
if(extraInfo)
|
||||||
|
debugPass_->render(commandBuffer, collection, extraInfo, target);
|
||||||
|
|
||||||
dofPass_->render(commandBuffer, *collection.camera.camera, target);
|
dofPass_->render(commandBuffer, *collection.camera.camera, target);
|
||||||
|
|
||||||
// reset after dof pass
|
// reset after dof pass
|
||||||
|
@ -308,6 +314,13 @@ RenderTarget* Renderer::createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTa
|
||||||
|
|
||||||
target->offscreenFramebuffers = new VkFramebuffer[numFrameResources];
|
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
|
// dof
|
||||||
target->nearFieldImages = new VkImage[numFrameResources];
|
target->nearFieldImages = new VkImage[numFrameResources];
|
||||||
target->nearFieldMemory = new VkDeviceMemory[numFrameResources];
|
target->nearFieldMemory = new VkDeviceMemory[numFrameResources];
|
||||||
|
@ -446,6 +459,63 @@ RenderTarget* Renderer::createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTa
|
||||||
vkCreateFramebuffer(device_, &framebufferInfo, nullptr, &target->offscreenFramebuffers[i]);
|
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
|
// near field color
|
||||||
{
|
{
|
||||||
VkImageCreateInfo imageCreateInfo = {};
|
VkImageCreateInfo imageCreateInfo = {};
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
class Renderer;
|
class Renderer;
|
||||||
|
|
||||||
|
using EntityID = uint64_t;
|
||||||
|
|
||||||
struct Context {
|
struct Context {
|
||||||
Renderer* renderer;
|
Renderer* renderer;
|
||||||
|
|
||||||
|
std::vector<EntityID> selectedEntities;
|
||||||
};
|
};
|
||||||
|
|
|
@ -50,7 +50,11 @@ void RendererWindow::render() {
|
||||||
if(target->extent.width != width || target->extent.height != height)
|
if(target->extent.width != width || target->extent.height != height)
|
||||||
target = context.renderer->createSurfaceRenderTarget(surface, target);
|
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);
|
vulkanInstance()->presentQueued(this);
|
||||||
requestUpdate();
|
requestUpdate();
|
||||||
|
|
|
@ -15,6 +15,16 @@ Hierarchy::Hierarchy(Context& context, QWidget* parent) : QWidget(parent), conte
|
||||||
listView = new QListView();
|
listView = new QListView();
|
||||||
layout->addWidget(listView);
|
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();
|
listModel = new QStringListModel();
|
||||||
listView->setModel(listModel);
|
listView->setModel(listModel);
|
||||||
|
|
||||||
|
|
Reference in a new issue