Add depth of field pass
This commit is contained in:
parent
491a9b67c7
commit
867d62edd4
14 changed files with 11524 additions and 40 deletions
|
@ -20,7 +20,8 @@ add_executable(Graph
|
|||
src/main.cpp
|
||||
src/renderer.cpp
|
||||
src/worldpass.cpp
|
||||
src/postpass.cpp)
|
||||
src/postpass.cpp
|
||||
src/dofpass.cpp)
|
||||
target_link_libraries(Graph PUBLIC SDL2::SDL2 SDL2::SDL2main Vulkan::Vulkan assimp::assimp)
|
||||
target_include_directories(Graph PUBLIC include)
|
||||
|
||||
|
@ -28,8 +29,12 @@ add_shaders(Graph
|
|||
shaders/triangle.vert
|
||||
shaders/triangle.frag
|
||||
shaders/post.vert
|
||||
shaders/post.frag)
|
||||
shaders/post.frag
|
||||
shaders/gfield.vert
|
||||
shaders/gfield.frag)
|
||||
|
||||
add_data(Graph
|
||||
data/suzanne.obj
|
||||
data/test.cim)
|
||||
data/test.cim
|
||||
data/bokeh.png
|
||||
data/scene.obj)
|
||||
|
|
BIN
data/bokeh.png
Normal file
BIN
data/bokeh.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
3120
data/scene.obj
Normal file
3120
data/scene.obj
Normal file
File diff suppressed because it is too large
Load diff
41
include/dofpass.h
Normal file
41
include/dofpass.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
class Renderer;
|
||||
struct RenderTarget;
|
||||
|
||||
class DoFPass {
|
||||
public:
|
||||
DoFPass(Renderer& renderer);
|
||||
~DoFPass();
|
||||
|
||||
void render(VkCommandBuffer commandBuffer, RenderTarget* target);
|
||||
|
||||
void createDescriptorSet(RenderTarget* target);
|
||||
|
||||
VkRenderPass getRenderPass() const {
|
||||
return renderPass_;
|
||||
}
|
||||
|
||||
private:
|
||||
void createRenderPass();
|
||||
void createDescriptorSetLayout();
|
||||
void createPipeline();
|
||||
void createBokehImage();
|
||||
void createDescriptorSet();
|
||||
|
||||
VkRenderPass renderPass_ = nullptr;
|
||||
|
||||
VkDescriptorSetLayout setLayout_ = nullptr;
|
||||
|
||||
VkPipelineLayout pipelineLayout_ = nullptr;
|
||||
VkPipeline pipeline_ = nullptr;
|
||||
|
||||
VkImage bokehImage_ = nullptr;
|
||||
VkDeviceMemory bokehMemory_ = nullptr;
|
||||
VkImageView bokehImageView_ = nullptr;
|
||||
VkSampler bokehSampler_ = nullptr;
|
||||
|
||||
Renderer& renderer_;
|
||||
};
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "worldpass.h"
|
||||
#include "postpass.h"
|
||||
#include "dofpass.h"
|
||||
|
||||
struct RenderTarget {
|
||||
VkSurfaceKHR surface = nullptr;
|
||||
|
@ -12,19 +13,36 @@ struct RenderTarget {
|
|||
VkExtent2D extent = {};
|
||||
uint32_t numImages = 0, currentImage = 0;
|
||||
|
||||
// swapwchain
|
||||
VkImage* swapchainImages = nullptr;
|
||||
VkImageView* swapchainImageViews = nullptr;
|
||||
VkFramebuffer* swapchainFramebuffers = nullptr;
|
||||
|
||||
// offscreen color
|
||||
VkImage* offscreenColorImages = nullptr;
|
||||
VkDeviceMemory* offscreenColorMemory = nullptr;
|
||||
VkImageView* offscreenColorImageViews = nullptr;
|
||||
|
||||
// offscreen depth
|
||||
VkImage* offscreenDepthImages = nullptr;
|
||||
VkDeviceMemory* offscreenDepthMemory = nullptr;
|
||||
VkImageView* offscreenDepthImageViews = nullptr;
|
||||
|
||||
VkFramebuffer* offscreenFramebuffers = nullptr;
|
||||
|
||||
// near field
|
||||
VkImage* nearFieldImages = nullptr;
|
||||
VkDeviceMemory* nearFieldMemory = nullptr;
|
||||
VkImageView* nearFieldImageViews = nullptr;
|
||||
|
||||
VkFramebuffer* nearFieldFramebuffers = nullptr;
|
||||
|
||||
// far field
|
||||
VkImage* farFieldImages = nullptr;
|
||||
VkDeviceMemory* farFieldMemory = nullptr;
|
||||
VkImageView* farFieldImageViews = nullptr;
|
||||
|
||||
VkFramebuffer* farFieldFramebuffers = nullptr;
|
||||
|
||||
VkCommandBuffer* commandBuffers = nullptr;
|
||||
|
||||
|
@ -33,6 +51,7 @@ struct RenderTarget {
|
|||
VkFence* fences = nullptr;
|
||||
|
||||
VkDescriptorSet* postSets = nullptr;
|
||||
VkDescriptorSet* dofSets = nullptr;
|
||||
};
|
||||
|
||||
class World;
|
||||
|
@ -65,6 +84,14 @@ public:
|
|||
VkDevice getDevice() const {
|
||||
return device_;
|
||||
}
|
||||
|
||||
VkQueue getGraphicsQueue() const {
|
||||
return graphicsQueue_;
|
||||
}
|
||||
|
||||
VkCommandPool getCommandPool() const {
|
||||
return commandPool_;
|
||||
}
|
||||
|
||||
VkRenderPass getRenderPass() const {
|
||||
return presentationRenderPass_;
|
||||
|
@ -114,4 +141,5 @@ private:
|
|||
|
||||
WorldPass* worldPass_ = nullptr;
|
||||
PostPass* postPass_ = nullptr;
|
||||
DoFPass* dofPass_ = nullptr;
|
||||
};
|
||||
|
|
7462
include/stb_image.h
Normal file
7462
include/stb_image.h
Normal file
File diff suppressed because it is too large
Load diff
31
shaders/gfield.frag
Normal file
31
shaders/gfield.frag
Normal file
|
@ -0,0 +1,31 @@
|
|||
#version 460 core
|
||||
|
||||
layout(location = 0) in vec2 inUV;
|
||||
layout(location = 1) in vec2 inPos;
|
||||
layout(location = 2) in float cocRadius;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
layout(binding = 0) uniform sampler2D bokehSampler;
|
||||
layout(binding = 1) uniform sampler2D sceneSampler;
|
||||
layout(binding = 2) uniform sampler2D depthSampler;
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
vec4 dpack;
|
||||
} pushConstants;
|
||||
|
||||
void main() {
|
||||
const vec2 res = vec2(pushConstants.dpack[2], pushConstants.dpack[3]);
|
||||
|
||||
outColor = texture(sceneSampler, vec2(inPos.x / res.x, inPos.y / res.y)) * texture(bokehSampler, inUV);
|
||||
outColor.a = (cocRadius / 9000.0);
|
||||
|
||||
if(pushConstants.dpack[0] == 0) {
|
||||
if(texture(depthSampler, gl_FragCoord.xy / res).r < pushConstants.dpack[1])
|
||||
discard;
|
||||
} else {
|
||||
if(texture(depthSampler, gl_FragCoord.xy / res).r > pushConstants.dpack[1])
|
||||
discard;
|
||||
}
|
||||
}
|
||||
|
45
shaders/gfield.vert
Normal file
45
shaders/gfield.vert
Normal file
|
@ -0,0 +1,45 @@
|
|||
#version 460 core
|
||||
|
||||
layout(location = 0) out vec2 outUV;
|
||||
layout(location = 1) out vec2 outLoc;
|
||||
layout(location = 2) out float cocRadius;
|
||||
|
||||
layout(binding = 2) uniform sampler2D depthSampler;
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
vec4 dpack;
|
||||
} pushConstants;
|
||||
|
||||
void main() {
|
||||
const vec2 res = vec2(pushConstants.dpack[2], pushConstants.dpack[3]);
|
||||
|
||||
const vec2 loc = vec2((gl_InstanceIndex % int(res.x)), ((gl_InstanceIndex / int(res.x)) % int(res.y)));
|
||||
outLoc = loc;
|
||||
|
||||
const float depth = texture(depthSampler, vec2(loc.x / res.x, loc.y / res.y)).r;
|
||||
float size = 0.0;
|
||||
|
||||
// dpack[0] is the field we are drawing (far = 0, near = 1)
|
||||
if(pushConstants.dpack[0] == 0) {
|
||||
if(depth > pushConstants.dpack[1])
|
||||
size = (depth - pushConstants.dpack[1]) * 500.0;
|
||||
} else {
|
||||
if(depth < pushConstants.dpack[1])
|
||||
size = (pushConstants.dpack[1] - depth) * 500.0;
|
||||
}
|
||||
|
||||
cocRadius = size;
|
||||
|
||||
outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
||||
|
||||
vec2 pos = outUV * 2.0 + -1.0;
|
||||
pos *= vec2(1.0 / res.x, 1.0 / res.y);
|
||||
pos *= min(size, 32.0);
|
||||
pos.x -= 1;
|
||||
pos.y -= 1;
|
||||
pos.x += loc.x / (res.x / 2.0);
|
||||
pos.y += loc.y / (res.y / 2.0);
|
||||
|
||||
gl_Position = vec4(pos, 0.0, 1.0);
|
||||
}
|
||||
|
|
@ -4,8 +4,29 @@ layout(location = 0) in vec2 inUV;
|
|||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
layout(binding = 0) uniform sampler2D offscreenSampler;
|
||||
layout(binding = 0) uniform sampler2D sceneSampler;
|
||||
layout(binding = 1) uniform sampler2D depthSampler;
|
||||
layout(binding = 2) uniform sampler2D nearFieldSampler;
|
||||
layout(binding = 3) uniform sampler2D farFieldSampler;
|
||||
|
||||
void main() {
|
||||
outColor = texture(offscreenSampler, inUV);
|
||||
void main() {
|
||||
vec3 sceneColor = texture(sceneSampler, inUV).rgb;
|
||||
|
||||
// alpha divide reconstruction
|
||||
vec3 farColor = texture(farFieldSampler, inUV).rgb / max(texture(farFieldSampler, inUV).a, 0.0001) * 0.02;
|
||||
vec3 nearColor = texture(nearFieldSampler, inUV).rgb / max(texture(nearFieldSampler, inUV).a, 0.0001) * 0.02;
|
||||
|
||||
// read coc stored in the alpha channel
|
||||
float coc = texture(farFieldSampler, inUV).a;
|
||||
|
||||
// transistion between out of focus and regular scene
|
||||
vec3 farColorBlurred = mix(sceneColor, farColor, clamp(coc, 0.0, 1.0));
|
||||
|
||||
// smoother transistion between the normal scene and the "out of focus" portions
|
||||
farColorBlurred = mix(sceneColor, farColorBlurred, clamp(0.5 * coc + 1.0, 0.0, 1.0));
|
||||
|
||||
//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));
|
||||
|
||||
outColor = vec4(farColorBlurred, 1.0);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,6 @@ layout(location = 0) out vec2 outUV;
|
|||
|
||||
void main() {
|
||||
outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
||||
gl_Position = vec4(outUV * 2.0f + -1.0f, 0.0f, 1.0f);
|
||||
gl_Position = vec4(outUV * 2.0 + -1.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
|
|
499
src/dofpass.cpp
Normal file
499
src/dofpass.cpp
Normal file
|
@ -0,0 +1,499 @@
|
|||
#include "dofpass.h"
|
||||
|
||||
#include <array>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
#include "renderer.h"
|
||||
|
||||
DoFPass::DoFPass(Renderer& renderer) : renderer_(renderer) {
|
||||
createRenderPass();
|
||||
createDescriptorSetLayout();
|
||||
createPipeline();
|
||||
createBokehImage();
|
||||
}
|
||||
|
||||
DoFPass::~DoFPass() {
|
||||
vkDestroySampler(renderer_.getDevice(), bokehSampler_, nullptr);
|
||||
vkDestroyImageView(renderer_.getDevice(), bokehImageView_, nullptr);
|
||||
vkFreeMemory(renderer_.getDevice(), bokehMemory_, nullptr);
|
||||
vkDestroyImage(renderer_.getDevice(), bokehImage_, nullptr);
|
||||
|
||||
vkDestroyPipeline(renderer_.getDevice(), pipeline_, nullptr);
|
||||
vkDestroyPipelineLayout(renderer_.getDevice(), pipelineLayout_, nullptr);
|
||||
|
||||
vkDestroyDescriptorSetLayout(renderer_.getDevice(), setLayout_, nullptr);
|
||||
|
||||
vkDestroyRenderPass(renderer_.getDevice(), renderPass_, nullptr);
|
||||
}
|
||||
|
||||
void DoFPass::render(VkCommandBuffer commandBuffer, RenderTarget* target) {
|
||||
VkViewport viewport = {};
|
||||
viewport.width = target->extent.width / 2;
|
||||
viewport.height = target->extent.height / 2;
|
||||
viewport.maxDepth = 1.0f;
|
||||
|
||||
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
||||
|
||||
VkRect2D scissor = {};
|
||||
scissor.extent.width = target->extent.width / 2;
|
||||
scissor.extent.height = target->extent.height / 2;
|
||||
|
||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||
|
||||
VkClearValue clearColor = {};
|
||||
|
||||
VkRenderPassBeginInfo renderPassBeginInfo = {};
|
||||
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
renderPassBeginInfo.framebuffer = target->farFieldFramebuffers[target->currentImage];
|
||||
renderPassBeginInfo.renderPass = renderPass_;
|
||||
renderPassBeginInfo.renderArea.extent.width = target->extent.width / 2;
|
||||
renderPassBeginInfo.renderArea.extent.height = target->extent.height / 2;
|
||||
renderPassBeginInfo.clearValueCount = 1;
|
||||
renderPassBeginInfo.pClearValues = &clearColor;
|
||||
|
||||
// far field
|
||||
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
glm::vec4 dpack;
|
||||
dpack[0] = 0;
|
||||
dpack[1] = 0.9581;
|
||||
dpack[2] = target->extent.width / 2;
|
||||
dpack[3] = target->extent.height / 2;
|
||||
|
||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_);
|
||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &target->dofSets[target->currentImage], 0, nullptr);
|
||||
|
||||
vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(glm::vec4), &dpack);
|
||||
|
||||
vkCmdDraw(commandBuffer, 3, (target->extent.width / 2) * (target->extent.height / 2), 0, 0);
|
||||
|
||||
vkCmdEndRenderPass(commandBuffer);
|
||||
|
||||
//near field
|
||||
renderPassBeginInfo.framebuffer = target->nearFieldFramebuffers[target->currentImage];
|
||||
|
||||
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_);
|
||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &target->dofSets[target->currentImage], 0, nullptr);
|
||||
|
||||
dpack[0] = 1;
|
||||
dpack[1] = 0.9581;
|
||||
|
||||
vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(glm::vec4), &dpack);
|
||||
|
||||
//FIXME: near field is bugged
|
||||
//vkCmdDraw(commandBuffer, 3, (target->extent.width / 2) * (target->extent.height / 2), 0, 0);
|
||||
|
||||
vkCmdEndRenderPass(commandBuffer);
|
||||
}
|
||||
|
||||
void DoFPass::createDescriptorSet(RenderTarget* target) {
|
||||
VkDescriptorSetAllocateInfo allocInfo = {};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
allocInfo.descriptorPool = renderer_.getDescriptorPool();
|
||||
allocInfo.descriptorSetCount = target->numImages;
|
||||
|
||||
// FIXME: lol what
|
||||
auto layouts = new VkDescriptorSetLayout[target->numImages];
|
||||
for(uint32_t i = 0; i < target->numImages; i++)
|
||||
layouts[i] = setLayout_;
|
||||
|
||||
allocInfo.pSetLayouts = layouts;
|
||||
|
||||
target->dofSets = new VkDescriptorSet[target->numImages];
|
||||
vkAllocateDescriptorSets(renderer_.getDevice(), &allocInfo, target->dofSets);
|
||||
|
||||
delete[] layouts;
|
||||
|
||||
for(uint32_t i = 0; i < target->numImages; i++) {
|
||||
VkDescriptorImageInfo bokehImageInfo = {};
|
||||
bokehImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
bokehImageInfo.imageView = bokehImageView_;
|
||||
bokehImageInfo.sampler = bokehSampler_;
|
||||
|
||||
VkDescriptorImageInfo sceneImageInfo = {};
|
||||
sceneImageInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
sceneImageInfo.imageView = target->offscreenColorImageViews[i];
|
||||
sceneImageInfo.sampler = bokehSampler_;
|
||||
|
||||
VkDescriptorImageInfo depthImageInfo = {};
|
||||
depthImageInfo.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;;
|
||||
depthImageInfo.imageView = target->offscreenDepthImageViews[i];
|
||||
depthImageInfo.sampler = bokehSampler_;
|
||||
|
||||
VkWriteDescriptorSet bokehDescriptorWrite = {};
|
||||
bokehDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
bokehDescriptorWrite.descriptorCount = 1;
|
||||
bokehDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
bokehDescriptorWrite.dstSet = target->dofSets[i];
|
||||
bokehDescriptorWrite.pImageInfo = &bokehImageInfo;
|
||||
|
||||
VkWriteDescriptorSet sceneDescriptorWrite = {};
|
||||
sceneDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
sceneDescriptorWrite.descriptorCount = 1;
|
||||
sceneDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
sceneDescriptorWrite.dstBinding = 1;
|
||||
sceneDescriptorWrite.dstSet = target->dofSets[i];
|
||||
sceneDescriptorWrite.pImageInfo = &sceneImageInfo;
|
||||
|
||||
VkWriteDescriptorSet depthDescriptorWrite = {};
|
||||
depthDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
depthDescriptorWrite.descriptorCount = 1;
|
||||
depthDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
depthDescriptorWrite.dstBinding = 2;
|
||||
depthDescriptorWrite.dstSet = target->dofSets[i];
|
||||
depthDescriptorWrite.pImageInfo = &depthImageInfo;
|
||||
|
||||
const std::array<VkWriteDescriptorSet, 3> descriptorWrites = {
|
||||
bokehDescriptorWrite,
|
||||
sceneDescriptorWrite,
|
||||
depthDescriptorWrite
|
||||
};
|
||||
|
||||
vkUpdateDescriptorSets(renderer_.getDevice(), descriptorWrites.size(), descriptorWrites.data(), 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void DoFPass::createRenderPass() {
|
||||
VkAttachmentDescription colorAttachment = {};
|
||||
colorAttachment.format = VK_FORMAT_R32G32B32A32_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_COLOR_ATTACHMENT_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;
|
||||
|
||||
VkRenderPassCreateInfo renderPassInfo = {};
|
||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
renderPassInfo.attachmentCount = 1;
|
||||
renderPassInfo.pAttachments = &colorAttachment;
|
||||
renderPassInfo.subpassCount = 1;
|
||||
renderPassInfo.pSubpasses = &subpass;
|
||||
|
||||
vkCreateRenderPass(renderer_.getDevice(), &renderPassInfo, nullptr, &renderPass_);
|
||||
}
|
||||
|
||||
void DoFPass::createDescriptorSetLayout() {
|
||||
VkDescriptorSetLayoutBinding bokehSamplerBinding = {};
|
||||
bokehSamplerBinding.descriptorCount = 1;
|
||||
bokehSamplerBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
bokehSamplerBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
|
||||
VkDescriptorSetLayoutBinding sceneSamplerBinding = {};
|
||||
sceneSamplerBinding.binding = 1;
|
||||
sceneSamplerBinding.descriptorCount = 1;
|
||||
sceneSamplerBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
sceneSamplerBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
|
||||
VkDescriptorSetLayoutBinding depthSamplerBinding = {};
|
||||
depthSamplerBinding.binding = 2;
|
||||
depthSamplerBinding.descriptorCount = 1;
|
||||
depthSamplerBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
depthSamplerBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
|
||||
const std::array<VkDescriptorSetLayoutBinding, 3> bindings = {
|
||||
bokehSamplerBinding,
|
||||
sceneSamplerBinding,
|
||||
depthSamplerBinding
|
||||
};
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
createInfo.bindingCount = bindings.size();
|
||||
createInfo.pBindings = bindings.data();
|
||||
|
||||
vkCreateDescriptorSetLayout(renderer_.getDevice(), &createInfo, nullptr, &setLayout_);
|
||||
}
|
||||
|
||||
void DoFPass::createPipeline() {
|
||||
VkShaderModule vertShaderModule = renderer_.createShader("shaders/gfield.vert.spv");
|
||||
VkShaderModule fragShaderModule = renderer_.createShader("shaders/gfield.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};
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
|
||||
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
|
||||
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.lineWidth = 1.0f;
|
||||
rasterizer.cullMode = VK_CULL_MODE_FRONT_BIT;
|
||||
rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
||||
|
||||
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;
|
||||
colorBlendAttachment.blendEnable = VK_TRUE;
|
||||
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
|
||||
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::vec4);
|
||||
pushConstant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | 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_);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void DoFPass::createBokehImage() {
|
||||
int width, height, channels;
|
||||
stbi_uc* pixels = stbi_load("data/bokeh.png", &width, &height, &channels, STBI_rgb_alpha);
|
||||
|
||||
VkImageCreateInfo imageCreateInfo = {};
|
||||
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageCreateInfo.extent.width = width;
|
||||
imageCreateInfo.extent.height = height;
|
||||
imageCreateInfo.extent.depth = 1;
|
||||
imageCreateInfo.mipLevels = 1;
|
||||
imageCreateInfo.arrayLayers = 1;
|
||||
imageCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
vkCreateImage(renderer_.getDevice(), &imageCreateInfo, nullptr, &bokehImage_);
|
||||
|
||||
VkMemoryRequirements memRequirements;
|
||||
vkGetImageMemoryRequirements(renderer_.getDevice(), bokehImage_, &memRequirements);
|
||||
|
||||
VkMemoryAllocateInfo allocInfo = {};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocInfo.allocationSize = memRequirements.size;
|
||||
allocInfo.memoryTypeIndex = renderer_.findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
vkAllocateMemory(renderer_.getDevice(), &allocInfo, nullptr, &bokehMemory_);
|
||||
vkBindImageMemory(renderer_.getDevice(), bokehImage_, bokehMemory_, 0);
|
||||
|
||||
VkBuffer stagingBuffer;
|
||||
VkDeviceMemory stagingMemory;
|
||||
|
||||
VkBufferCreateInfo bufferInfo = {};
|
||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
bufferInfo.size = width * height * 4;
|
||||
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
vkCreateBuffer(renderer_.getDevice(), &bufferInfo, nullptr, &stagingBuffer);
|
||||
|
||||
vkGetBufferMemoryRequirements(renderer_.getDevice(), stagingBuffer, &memRequirements);
|
||||
|
||||
allocInfo = {};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocInfo.allocationSize = memRequirements.size;
|
||||
allocInfo.memoryTypeIndex = renderer_.findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
vkAllocateMemory(renderer_.getDevice(), &allocInfo, nullptr, &stagingMemory);
|
||||
vkBindBufferMemory(renderer_.getDevice(), stagingBuffer, stagingMemory, 0);
|
||||
|
||||
void* data;
|
||||
vkMapMemory(renderer_.getDevice(), stagingMemory, 0, width * height * 4, 0, &data);
|
||||
memcpy(data, pixels, width * height * 4);
|
||||
vkUnmapMemory(renderer_.getDevice(), stagingMemory);
|
||||
|
||||
stbi_image_free(pixels);
|
||||
|
||||
VkCommandBufferAllocateInfo bufferAllocateInfo = {};
|
||||
bufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
bufferAllocateInfo.commandPool = renderer_.getCommandPool();
|
||||
bufferAllocateInfo.commandBufferCount = 1;
|
||||
|
||||
VkCommandBuffer commandBuffer = nullptr;
|
||||
vkAllocateCommandBuffers(renderer_.getDevice(), &bufferAllocateInfo, &commandBuffer);
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo = {};
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
|
||||
vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
||||
|
||||
// change layout to transfer dst
|
||||
{
|
||||
VkImageMemoryBarrier imageMemoryBarrier = {};
|
||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
imageMemoryBarrier.image = bokehImage_;
|
||||
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
imageMemoryBarrier.subresourceRange.layerCount = 1;
|
||||
imageMemoryBarrier.subresourceRange.levelCount = 1;
|
||||
|
||||
vkCmdPipelineBarrier(
|
||||
commandBuffer,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0,
|
||||
0, nullptr,
|
||||
0, nullptr,
|
||||
1, &imageMemoryBarrier);
|
||||
}
|
||||
|
||||
VkBufferImageCopy region = {};
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
region.imageExtent.width = width;
|
||||
region.imageExtent.height = height;
|
||||
region.imageExtent.depth = 1;
|
||||
|
||||
vkCmdCopyBufferToImage(
|
||||
commandBuffer,
|
||||
stagingBuffer,
|
||||
bokehImage_,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
1,
|
||||
®ion
|
||||
);
|
||||
|
||||
// change layout to shader read only
|
||||
{
|
||||
VkImageMemoryBarrier imageMemoryBarrier = {};
|
||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
imageMemoryBarrier.image = bokehImage_;
|
||||
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
imageMemoryBarrier.subresourceRange.layerCount = 1;
|
||||
imageMemoryBarrier.subresourceRange.levelCount = 1;
|
||||
|
||||
vkCmdPipelineBarrier(
|
||||
commandBuffer,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
0,
|
||||
0, nullptr,
|
||||
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(renderer_.getDevice(), &fenceCreateInfo, nullptr, &fence);
|
||||
|
||||
vkQueueSubmit(renderer_.getGraphicsQueue(), 1, &submitInfo, fence);
|
||||
|
||||
vkWaitForFences(renderer_.getDevice(), 1, &fence, VK_TRUE, -1);
|
||||
vkDestroyFence(renderer_.getDevice(), fence, nullptr);
|
||||
|
||||
vkFreeCommandBuffers(renderer_.getDevice(), renderer_.getCommandPool(), 1, &commandBuffer);
|
||||
|
||||
vkFreeMemory(renderer_.getDevice(), stagingMemory, nullptr);
|
||||
vkDestroyBuffer(renderer_.getDevice(), stagingBuffer, nullptr);
|
||||
|
||||
VkImageViewCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
createInfo.image = bokehImage_;
|
||||
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
createInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
createInfo.subresourceRange.levelCount = 1;
|
||||
createInfo.subresourceRange.layerCount = 1;
|
||||
|
||||
vkCreateImageView(renderer_.getDevice(), &createInfo, nullptr, &bokehImageView_);
|
||||
|
||||
VkSamplerCreateInfo samplerInfo = {};
|
||||
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||
samplerInfo.magFilter = VK_FILTER_LINEAR;
|
||||
samplerInfo.minFilter = VK_FILTER_LINEAR;
|
||||
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
||||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
||||
samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
|
||||
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
|
||||
vkCreateSampler(renderer_.getDevice(), &samplerInfo, nullptr, &bokehSampler_);
|
||||
}
|
34
src/main.cpp
34
src/main.cpp
|
@ -101,21 +101,27 @@ Mesh* loadMesh(const char* path) {
|
|||
Assimp::Importer importer;
|
||||
const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate);
|
||||
|
||||
aiMesh* m = scene->mMeshes[0];
|
||||
Mesh* mesh = new Mesh();
|
||||
|
||||
for(unsigned int i = 0; i < m->mNumVertices; i++) {
|
||||
Vertex vertex;
|
||||
vertex.position = glm::vec3(m->mVertices[i].x, m->mVertices[i].y, m->mVertices[i].z);
|
||||
vertex.normal = glm::vec3(m->mNormals[i].x, m->mNormals[i].y, m->mNormals[i].z);
|
||||
unsigned int indexOffset = 0;
|
||||
for(unsigned mi = 0; mi < scene->mNumMeshes; mi++) {
|
||||
aiMesh* m = scene->mMeshes[mi];
|
||||
|
||||
for(unsigned int i = 0; i < m->mNumVertices; i++) {
|
||||
Vertex vertex;
|
||||
vertex.position = glm::vec3(m->mVertices[i].x, m->mVertices[i].y, m->mVertices[i].z);
|
||||
vertex.normal = glm::vec3(m->mNormals[i].x, m->mNormals[i].y, m->mNormals[i].z);
|
||||
|
||||
mesh->vertices.push_back(vertex);
|
||||
}
|
||||
mesh->vertices.push_back(vertex);
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < m->mNumFaces; i++) {
|
||||
aiFace face = m->mFaces[i];
|
||||
for(unsigned int j = 0; j < face.mNumIndices; j++)
|
||||
mesh->indices.push_back(face.mIndices[j]);
|
||||
for(unsigned int i = 0; i < m->mNumFaces; i++) {
|
||||
aiFace face = m->mFaces[i];
|
||||
for(unsigned int j = 0; j < face.mNumIndices; j++)
|
||||
mesh->indices.push_back(indexOffset + face.mIndices[j]);
|
||||
}
|
||||
|
||||
indexOffset += m->mNumVertices;
|
||||
}
|
||||
|
||||
renderer->fillMeshBuffers(mesh);
|
||||
|
@ -228,12 +234,12 @@ int main(int argc, char* argv[]) {
|
|||
world.lights.push_back(light);
|
||||
|
||||
Camera camera;
|
||||
camera.position.z = 3;
|
||||
camera.position = {5.0, 5.0, 5.0};
|
||||
|
||||
if(cinematicMode)
|
||||
cinematic = loadCinematic(argv[2]);
|
||||
else
|
||||
world.meshes.push_back(loadMesh("data/suzanne.obj"));
|
||||
world.meshes.push_back(loadMesh("data/scene.obj"));
|
||||
|
||||
float currentTime = 0.0f, lastTime = 0.0f;
|
||||
Shot* currentShot = nullptr;
|
||||
|
@ -262,7 +268,7 @@ int main(int argc, char* argv[]) {
|
|||
target = renderer->createSurfaceRenderTarget(surface, target);
|
||||
}
|
||||
|
||||
if(event.type == SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_F12) {
|
||||
if(event.type == SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_F7) {
|
||||
renderer->takeScreenshot("screenshot.ppm", target);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,19 +44,65 @@ void PostPass::createDescriptorSet(RenderTarget* target) {
|
|||
delete[] layouts;
|
||||
|
||||
for(uint32_t i = 0; i < target->numImages; i++) {
|
||||
VkDescriptorImageInfo imageInfo = {};
|
||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
imageInfo.imageView = target->offscreenColorImageViews[i];
|
||||
imageInfo.sampler = offscreenSampler_;
|
||||
VkDescriptorImageInfo sceneImageInfo = {};
|
||||
sceneImageInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
sceneImageInfo.imageView = target->offscreenColorImageViews[i];
|
||||
sceneImageInfo.sampler = offscreenSampler_;
|
||||
|
||||
VkDescriptorImageInfo depthImageInfo = {};
|
||||
depthImageInfo.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;;
|
||||
depthImageInfo.imageView = target->offscreenDepthImageViews[i];
|
||||
depthImageInfo.sampler = offscreenSampler_;
|
||||
|
||||
VkDescriptorImageInfo nearFieldImageInfo = {};
|
||||
nearFieldImageInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
nearFieldImageInfo.imageView = target->nearFieldImageViews[i];
|
||||
nearFieldImageInfo.sampler = offscreenSampler_;
|
||||
|
||||
VkDescriptorImageInfo farFieldImageInfo = {};
|
||||
farFieldImageInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
farFieldImageInfo.imageView = target->farFieldImageViews[i];
|
||||
farFieldImageInfo.sampler = offscreenSampler_;
|
||||
|
||||
VkWriteDescriptorSet descriptorWrite = {};
|
||||
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptorWrite.descriptorCount = 1;
|
||||
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
descriptorWrite.dstSet = target->postSets[i];
|
||||
descriptorWrite.pImageInfo = &imageInfo;
|
||||
VkWriteDescriptorSet sceneDescriptorWrite = {};
|
||||
sceneDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
sceneDescriptorWrite.descriptorCount = 1;
|
||||
sceneDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
sceneDescriptorWrite.dstSet = target->postSets[i];
|
||||
sceneDescriptorWrite.pImageInfo = &sceneImageInfo;
|
||||
|
||||
VkWriteDescriptorSet depthDescriptorWrite = {};
|
||||
depthDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
depthDescriptorWrite.descriptorCount = 1;
|
||||
depthDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
depthDescriptorWrite.dstBinding = 1;
|
||||
depthDescriptorWrite.dstSet = target->postSets[i];
|
||||
depthDescriptorWrite.pImageInfo = &depthImageInfo;
|
||||
|
||||
VkWriteDescriptorSet nearFieldDescriptorWrite = {};
|
||||
nearFieldDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
nearFieldDescriptorWrite.descriptorCount = 1;
|
||||
nearFieldDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
nearFieldDescriptorWrite.dstBinding = 2;
|
||||
nearFieldDescriptorWrite.dstSet = target->postSets[i];
|
||||
nearFieldDescriptorWrite.pImageInfo = &nearFieldImageInfo;
|
||||
|
||||
VkWriteDescriptorSet farFieldDescriptorWrite = {};
|
||||
farFieldDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
farFieldDescriptorWrite.descriptorCount = 1;
|
||||
farFieldDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
farFieldDescriptorWrite.dstBinding = 3;
|
||||
farFieldDescriptorWrite.dstSet = target->postSets[i];
|
||||
farFieldDescriptorWrite.pImageInfo = &farFieldImageInfo;
|
||||
|
||||
const std::array<VkWriteDescriptorSet, 4> descriptorWrites = {
|
||||
sceneDescriptorWrite,
|
||||
depthDescriptorWrite,
|
||||
nearFieldDescriptorWrite,
|
||||
farFieldDescriptorWrite
|
||||
};
|
||||
|
||||
vkUpdateDescriptorSets(renderer_.getDevice(), 1, &descriptorWrite, 0, nullptr);
|
||||
vkUpdateDescriptorSets(renderer_.getDevice(), descriptorWrites.size(), descriptorWrites.data(), 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,11 +111,36 @@ void PostPass::createDescriptorSetLayout() {
|
|||
offscreenSamplerBinding.descriptorCount = 1;
|
||||
offscreenSamplerBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
offscreenSamplerBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
|
||||
VkDescriptorSetLayoutBinding depthSamplerBinding = {};
|
||||
depthSamplerBinding.binding = 1;
|
||||
depthSamplerBinding.descriptorCount = 1;
|
||||
depthSamplerBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
depthSamplerBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
|
||||
VkDescriptorSetLayoutBinding nearFieldSamplerBinding = {};
|
||||
nearFieldSamplerBinding.binding = 2;
|
||||
nearFieldSamplerBinding.descriptorCount = 1;
|
||||
nearFieldSamplerBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
nearFieldSamplerBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
|
||||
VkDescriptorSetLayoutBinding farFieldSamplerBinding = {};
|
||||
farFieldSamplerBinding.binding = 3;
|
||||
farFieldSamplerBinding.descriptorCount = 1;
|
||||
farFieldSamplerBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
farFieldSamplerBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
|
||||
const std::array<VkDescriptorSetLayoutBinding, 4> bindings = {
|
||||
offscreenSamplerBinding,
|
||||
depthSamplerBinding,
|
||||
nearFieldSamplerBinding,
|
||||
farFieldSamplerBinding
|
||||
};
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
createInfo.bindingCount = 1;
|
||||
createInfo.pBindings = &offscreenSamplerBinding;
|
||||
createInfo.bindingCount = bindings.size();
|
||||
createInfo.pBindings = bindings.data();
|
||||
|
||||
vkCreateDescriptorSetLayout(renderer_.getDevice(), &createInfo, nullptr, &setLayout_);
|
||||
}
|
||||
|
|
167
src/renderer.cpp
167
src/renderer.cpp
|
@ -25,11 +25,13 @@ Renderer::Renderer() {
|
|||
|
||||
worldPass_ = new WorldPass(*this);
|
||||
postPass_ = new PostPass(*this);
|
||||
dofPass_ = new DoFPass(*this);
|
||||
}
|
||||
|
||||
Renderer::~Renderer() {
|
||||
vkDeviceWaitIdle(device_);
|
||||
|
||||
delete dofPass_;
|
||||
delete postPass_;
|
||||
delete worldPass_;
|
||||
|
||||
|
@ -74,7 +76,12 @@ void Renderer::render(World& world, Camera& camera, RenderTarget* target) {
|
|||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||
|
||||
worldPass_->render(commandBuffer, world, camera, target);
|
||||
|
||||
dofPass_->render(commandBuffer, target);
|
||||
|
||||
// reset after dof pass
|
||||
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||
|
||||
VkClearValue clearColor = {};
|
||||
|
||||
VkRenderPassBeginInfo renderPassBeginInfo = {};
|
||||
|
@ -188,6 +195,14 @@ RenderTarget* Renderer::createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTa
|
|||
target->offscreenDepthMemory = new VkDeviceMemory[swapchainImageCount];
|
||||
target->offscreenDepthImageViews = new VkImageView[swapchainImageCount];
|
||||
target->offscreenFramebuffers = new VkFramebuffer[swapchainImageCount];
|
||||
target->nearFieldImages = new VkImage[swapchainImageCount];
|
||||
target->nearFieldMemory = new VkDeviceMemory[swapchainImageCount];
|
||||
target->nearFieldImageViews = new VkImageView[swapchainImageCount];
|
||||
target->nearFieldFramebuffers = new VkFramebuffer[swapchainImageCount];
|
||||
target->farFieldImages = new VkImage[swapchainImageCount];
|
||||
target->farFieldMemory = new VkDeviceMemory[swapchainImageCount];
|
||||
target->farFieldImageViews = new VkImageView[swapchainImageCount];
|
||||
target->farFieldFramebuffers = new VkFramebuffer[swapchainImageCount];
|
||||
for(uint32_t i = 0; i < swapchainImageCount; i++) {
|
||||
// swapchain image view
|
||||
{
|
||||
|
@ -273,7 +288,7 @@ RenderTarget* Renderer::createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTa
|
|||
imageCreateInfo.arrayLayers = 1;
|
||||
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageCreateInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
imageCreateInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
|
||||
vkCreateImage(device_, &imageCreateInfo, nullptr, &target->offscreenDepthImages[i]);
|
||||
|
||||
|
@ -321,9 +336,124 @@ RenderTarget* Renderer::createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTa
|
|||
|
||||
vkCreateFramebuffer(device_, &framebufferInfo, nullptr, &target->offscreenFramebuffers[i]);
|
||||
}
|
||||
|
||||
// near field color
|
||||
{
|
||||
VkImageCreateInfo imageCreateInfo = {};
|
||||
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageCreateInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||
imageCreateInfo.extent.width = target->extent.width / 2;
|
||||
imageCreateInfo.extent.height = target->extent.height / 2;
|
||||
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->nearFieldImages[i]);
|
||||
|
||||
VkMemoryRequirements memoryRequirements = {};
|
||||
vkGetImageMemoryRequirements(device_, target->nearFieldImages[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->nearFieldMemory[i]);
|
||||
vkBindImageMemory(device_, target->nearFieldImages[i], target->nearFieldMemory[i], 0);
|
||||
}
|
||||
|
||||
// near field image view
|
||||
{
|
||||
VkImageViewCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
createInfo.image = target->nearFieldImages[i];
|
||||
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
createInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
createInfo.subresourceRange.levelCount = 1;
|
||||
createInfo.subresourceRange.layerCount = 1;
|
||||
|
||||
vkCreateImageView(device_, &createInfo, nullptr, &target->nearFieldImageViews[i]);
|
||||
}
|
||||
|
||||
// near field framebuffer
|
||||
{
|
||||
VkFramebufferCreateInfo framebufferInfo = {};
|
||||
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
framebufferInfo.renderPass = dofPass_->getRenderPass();
|
||||
framebufferInfo.attachmentCount = 1;
|
||||
framebufferInfo.pAttachments = &target->nearFieldImageViews[i];
|
||||
framebufferInfo.width = target->extent.width / 2;
|
||||
framebufferInfo.height = target->extent.height / 2;
|
||||
framebufferInfo.layers = 1;
|
||||
|
||||
vkCreateFramebuffer(device_, &framebufferInfo, nullptr, &target->nearFieldFramebuffers[i]);
|
||||
}
|
||||
|
||||
// far field color
|
||||
{
|
||||
VkImageCreateInfo imageCreateInfo = {};
|
||||
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageCreateInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||
imageCreateInfo.extent.width = target->extent.width / 2;
|
||||
imageCreateInfo.extent.height = target->extent.height / 2;
|
||||
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->farFieldImages[i]);
|
||||
|
||||
VkMemoryRequirements memoryRequirements = {};
|
||||
vkGetImageMemoryRequirements(device_, target->farFieldImages[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->farFieldMemory[i]);
|
||||
vkBindImageMemory(device_, target->farFieldImages[i], target->farFieldMemory[i], 0);
|
||||
}
|
||||
|
||||
// far field image view
|
||||
{
|
||||
VkImageViewCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
createInfo.image = target->farFieldImages[i];
|
||||
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
createInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
createInfo.subresourceRange.levelCount = 1;
|
||||
createInfo.subresourceRange.layerCount = 1;
|
||||
|
||||
vkCreateImageView(device_, &createInfo, nullptr, &target->farFieldImageViews[i]);
|
||||
}
|
||||
|
||||
// far field framebuffer
|
||||
{
|
||||
VkFramebufferCreateInfo framebufferInfo = {};
|
||||
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
framebufferInfo.renderPass = dofPass_->getRenderPass();
|
||||
framebufferInfo.attachmentCount = 1;
|
||||
framebufferInfo.pAttachments = &target->farFieldImageViews[i];
|
||||
framebufferInfo.width = target->extent.width / 2;
|
||||
framebufferInfo.height = target->extent.height / 2;
|
||||
framebufferInfo.layers = 1;
|
||||
|
||||
vkCreateFramebuffer(device_, &framebufferInfo, nullptr, &target->farFieldFramebuffers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
postPass_->createDescriptorSet(target);
|
||||
dofPass_->createDescriptorSet(target);
|
||||
|
||||
VkCommandBufferAllocateInfo allocateInfo = {};
|
||||
allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
|
@ -371,6 +501,18 @@ void Renderer::destroyRenderTarget(RenderTarget* target) {
|
|||
vkFreeDescriptorSets(device_, descriptorPool_, target->numImages, target->postSets);
|
||||
|
||||
for(uint32_t i = 0; i < target->numImages; i++) {
|
||||
vkDestroyFramebuffer(device_, target->nearFieldFramebuffers[i], nullptr);
|
||||
|
||||
vkDestroyImageView(device_, target->nearFieldImageViews[i], nullptr);
|
||||
vkFreeMemory(device_, target->nearFieldMemory[i], nullptr);
|
||||
vkDestroyImage(device_, target->nearFieldImages[i], nullptr);
|
||||
|
||||
vkDestroyFramebuffer(device_, target->farFieldFramebuffers[i], nullptr);
|
||||
|
||||
vkDestroyImageView(device_, target->farFieldImageViews[i], nullptr);
|
||||
vkFreeMemory(device_, target->farFieldMemory[i], nullptr);
|
||||
vkDestroyImage(device_, target->farFieldImages[i], nullptr);
|
||||
|
||||
vkDestroyFramebuffer(device_, target->offscreenFramebuffers[i], nullptr);
|
||||
|
||||
vkDestroyImageView(device_, target->offscreenDepthImageViews[i], nullptr);
|
||||
|
@ -384,11 +526,23 @@ void Renderer::destroyRenderTarget(RenderTarget* target) {
|
|||
vkDestroyFramebuffer(device_, target->swapchainFramebuffers[i], nullptr);
|
||||
vkDestroyImageView(device_, target->swapchainImageViews[i], nullptr);
|
||||
}
|
||||
|
||||
|
||||
delete[] target->nearFieldFramebuffers;
|
||||
delete[] target->nearFieldImageViews;
|
||||
delete[] target->nearFieldMemory;
|
||||
delete[] target->nearFieldImages;
|
||||
|
||||
delete[] target->farFieldFramebuffers;
|
||||
delete[] target->farFieldImageViews;
|
||||
delete[] target->farFieldMemory;
|
||||
delete[] target->farFieldImages;
|
||||
|
||||
delete[] target->offscreenFramebuffers;
|
||||
|
||||
delete[] target->offscreenDepthImageViews;
|
||||
delete[] target->offscreenDepthMemory;
|
||||
delete[] target->offscreenDepthImages;
|
||||
|
||||
delete[] target->offscreenColorImageViews;
|
||||
delete[] target->offscreenColorMemory;
|
||||
delete[] target->offscreenColorImages;
|
||||
|
@ -397,6 +551,7 @@ void Renderer::destroyRenderTarget(RenderTarget* target) {
|
|||
delete[] target->swapchainImageViews;
|
||||
delete[] target->swapchainImages;
|
||||
|
||||
delete[] target->dofSets;
|
||||
delete[] target->postSets;
|
||||
|
||||
vkDestroySwapchainKHR(device_, target->swapchain, nullptr);
|
||||
|
@ -872,8 +1027,8 @@ void Renderer::createPresentationRenderPass() {
|
|||
|
||||
void Renderer::createDescriptorPool() {
|
||||
const std::array<VkDescriptorPoolSize, 2> poolSizes = {
|
||||
VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 15},
|
||||
VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 15}
|
||||
VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 25},
|
||||
VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 25}
|
||||
};
|
||||
|
||||
VkDescriptorPoolCreateInfo poolInfo = {};
|
||||
|
@ -881,7 +1036,7 @@ void Renderer::createDescriptorPool() {
|
|||
poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
|
||||
poolInfo.poolSizeCount = poolSizes.size();
|
||||
poolInfo.pPoolSizes = poolSizes.data();
|
||||
poolInfo.maxSets = 15;
|
||||
poolInfo.maxSets = 25;
|
||||
|
||||
vkCreateDescriptorPool(device_, &poolInfo, nullptr, &descriptorPool_);
|
||||
}
|
||||
|
|
Reference in a new issue