Add shadow pass
This commit is contained in:
parent
af1b3b9845
commit
78f56d1509
12 changed files with 439 additions and 35 deletions
|
@ -51,7 +51,8 @@ add_executable(Graph
|
||||||
src/postpass.cpp
|
src/postpass.cpp
|
||||||
src/dofpass.cpp
|
src/dofpass.cpp
|
||||||
src/imguipass.cpp
|
src/imguipass.cpp
|
||||||
src/skypass.cpp)
|
src/skypass.cpp
|
||||||
|
src/shadowpass.cpp)
|
||||||
target_compile_options(Graph
|
target_compile_options(Graph
|
||||||
PUBLIC
|
PUBLIC
|
||||||
-fno-exceptions
|
-fno-exceptions
|
||||||
|
@ -81,7 +82,8 @@ add_shaders(Graph
|
||||||
shaders/imgui.vert
|
shaders/imgui.vert
|
||||||
shaders/imgui.frag
|
shaders/imgui.frag
|
||||||
shaders/sky.vert
|
shaders/sky.vert
|
||||||
shaders/sky.frag)
|
shaders/sky.frag
|
||||||
|
shaders/shadow.vert)
|
||||||
|
|
||||||
add_data(Graph
|
add_data(Graph
|
||||||
data/suzanne.obj
|
data/suzanne.obj
|
||||||
|
|
|
@ -10,6 +10,8 @@ enum class LightType {
|
||||||
class Light {
|
class Light {
|
||||||
public:
|
public:
|
||||||
LightType type = LightType::Point;
|
LightType type = LightType::Point;
|
||||||
glm::vec3 position = glm::vec3(0), direction = glm::vec3(0);
|
glm::vec3 position = glm::vec3(0);
|
||||||
glm::vec3 color = glm::vec3(1);
|
glm::vec3 color = glm::vec3(1);
|
||||||
|
|
||||||
|
glm::mat4 matrix = glm::mat4(1.0f);
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "dofpass.h"
|
#include "dofpass.h"
|
||||||
#include "imguipass.h"
|
#include "imguipass.h"
|
||||||
#include "skypass.h"
|
#include "skypass.h"
|
||||||
|
#include "shadowpass.h"
|
||||||
|
|
||||||
constexpr int numFrameResources = 2;
|
constexpr int numFrameResources = 2;
|
||||||
|
|
||||||
|
@ -128,6 +129,10 @@ public:
|
||||||
return *worldPass_;
|
return *worldPass_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShadowPass& getShadowPass() const {
|
||||||
|
return *shadowPass_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createInstance();
|
void createInstance();
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -174,4 +179,5 @@ private:
|
||||||
DoFPass* dofPass_ = nullptr;
|
DoFPass* dofPass_ = nullptr;
|
||||||
ImGuiPass* imguiPass_ = nullptr;
|
ImGuiPass* imguiPass_ = nullptr;
|
||||||
SkyPass* skyPass_ = nullptr;
|
SkyPass* skyPass_ = nullptr;
|
||||||
|
ShadowPass* shadowPass_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
40
include/shadowpass.h
Normal file
40
include/shadowpass.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
class Renderer;
|
||||||
|
class World;
|
||||||
|
|
||||||
|
class ShadowPass {
|
||||||
|
public:
|
||||||
|
ShadowPass(Renderer& renderer);
|
||||||
|
~ShadowPass();
|
||||||
|
|
||||||
|
void render(VkCommandBuffer commandBuffer, World& world);
|
||||||
|
|
||||||
|
VkImageView getImageView() const {
|
||||||
|
return shadowImageView_;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSampler getSampler() const {
|
||||||
|
return shadowSampler_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void createRenderPass();
|
||||||
|
void createFramebuffer();
|
||||||
|
void createPipeline();
|
||||||
|
|
||||||
|
VkRenderPass renderPass_ = nullptr;
|
||||||
|
|
||||||
|
VkImage shadowImage_ = nullptr;
|
||||||
|
VkDeviceMemory shadowMemory_ = nullptr;
|
||||||
|
VkImageView shadowImageView_ = nullptr;
|
||||||
|
VkFramebuffer shadowFramebuffer_ = nullptr;
|
||||||
|
VkSampler shadowSampler_ = nullptr;
|
||||||
|
|
||||||
|
VkPipeline pipeline_ = nullptr;
|
||||||
|
VkPipelineLayout pipelineLayout_ = nullptr;
|
||||||
|
|
||||||
|
Renderer& renderer_;
|
||||||
|
};
|
|
@ -1,8 +1,9 @@
|
||||||
#version 460 core
|
#version 460 core
|
||||||
|
|
||||||
layout(location = 0) in vec3 inFragPos;
|
layout(location = 0) in vec3 inFragPos;
|
||||||
layout(location = 1) in vec3 inNormal;
|
layout(location = 1) in vec4 inShadowPos;
|
||||||
layout(location = 2) in vec2 inUV;
|
layout(location = 2) in vec3 inNormal;
|
||||||
|
layout(location = 3) in vec2 inUV;
|
||||||
|
|
||||||
layout(location = 0) out vec4 outColor;
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
@ -15,8 +16,41 @@ layout(set = 0, binding = 0) uniform Lights {
|
||||||
Light lights[32];
|
Light lights[32];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
layout(set = 0, binding = 1) uniform sampler2D shadowSampler;
|
||||||
layout(set = 1, binding = 0) uniform sampler2D albedoSampler;
|
layout(set = 1, binding = 0) uniform sampler2D albedoSampler;
|
||||||
|
|
||||||
|
float textureProj(vec4 P, vec2 off) {
|
||||||
|
const vec4 shadowCoord = P / P.w; // perspective divide
|
||||||
|
|
||||||
|
float shadow = 1.0;
|
||||||
|
if(shadowCoord.z > -1.0 && shadowCoord.z < 1.0) {
|
||||||
|
const float dist = texture(shadowSampler, shadowCoord.st + off).r;
|
||||||
|
if(shadowCoord.w > 0.0 && dist < shadowCoord.z)
|
||||||
|
shadow = 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
float filterPCF(vec4 sc) {
|
||||||
|
const ivec2 texDim = textureSize(shadowSampler, 0);
|
||||||
|
const float scale = 1.5;
|
||||||
|
const float dx = scale * 1.0 / float(texDim.x);
|
||||||
|
const float dy = scale * 1.0 / float(texDim.y);
|
||||||
|
const int range = 2;
|
||||||
|
|
||||||
|
float shadowFactor = 0.0;
|
||||||
|
int count = 0;
|
||||||
|
for(int x = -range; x <= range; x++) {
|
||||||
|
for(int y = -range; y <= range; y++) {
|
||||||
|
shadowFactor += textureProj(sc, vec2(dx * x, dy * y));
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shadowFactor / count;
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec3 diffuse = vec3(0);
|
vec3 diffuse = vec3(0);
|
||||||
for(int i = 0; i < 32; i++) {
|
for(int i = 0; i < 32; i++) {
|
||||||
|
@ -29,7 +63,7 @@ void main() {
|
||||||
lightDir = normalize(-lights[i].direction.xyz);
|
lightDir = normalize(-lights[i].direction.xyz);
|
||||||
|
|
||||||
const float diff = max(dot(norm, lightDir), 0.0);
|
const float diff = max(dot(norm, lightDir), 0.0);
|
||||||
diffuse += vec3(diff) * lights[i].color;
|
diffuse += vec3(diff) * lights[i].color * filterPCF(inShadowPos / inShadowPos.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
outColor = vec4(vec3(0.1) + diffuse * texture(albedoSampler, inUV).rgb, 1.0);
|
outColor = vec4(vec3(0.1) + diffuse * texture(albedoSampler, inUV).rgb, 1.0);
|
||||||
|
|
|
@ -5,16 +5,24 @@ layout(location = 1) in vec3 inNormal;
|
||||||
layout(location = 2) in vec2 inUV;
|
layout(location = 2) in vec2 inUV;
|
||||||
|
|
||||||
layout(location = 0) out vec3 outFragPos;
|
layout(location = 0) out vec3 outFragPos;
|
||||||
layout(location = 1) out vec3 outNormal;
|
layout(location = 1) out vec4 outShadowPos;
|
||||||
layout(location = 2) out vec2 outUV;
|
layout(location = 2) out vec3 outNormal;
|
||||||
|
layout(location = 3) out vec2 outUV;
|
||||||
|
|
||||||
layout(push_constant) uniform PushConstants {
|
layout(push_constant) uniform PushConstants {
|
||||||
mat4 mvp;
|
mat4 vp, lightSpace;
|
||||||
} pushConstants;
|
} pushConstants;
|
||||||
|
|
||||||
|
const mat4 biasMat = mat4(
|
||||||
|
0.5, 0.0, 0.0, 0.0,
|
||||||
|
0.0, 0.5, 0.0, 0.0,
|
||||||
|
0.0, 0.0, 1.0, 0.0,
|
||||||
|
0.5, 0.5, 0.0, 1.0);
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = pushConstants.mvp * vec4(inPosition, 1.0);
|
gl_Position = pushConstants.vp * vec4(inPosition, 1.0);
|
||||||
outFragPos = inPosition;
|
outFragPos = inPosition;
|
||||||
|
outShadowPos = (biasMat * pushConstants.lightSpace) * vec4(inPosition, 1.0);
|
||||||
outNormal = inNormal;
|
outNormal = inNormal;
|
||||||
outUV = inUV;
|
outUV = inUV;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,24 +9,24 @@ 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;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec3 sceneColor = texture(sceneSampler, inUV).rgb;
|
vec3 sceneColor = texture(sceneSampler, inUV).rgb;
|
||||||
|
|
||||||
// alpha divide reconstruction
|
// alpha divide reconstruction
|
||||||
vec3 farColor = texture(farFieldSampler, inUV).rgb / max(texture(farFieldSampler, inUV).a, 0.0001) * 0.02;
|
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;
|
vec3 nearColor = texture(nearFieldSampler, inUV).rgb / max(texture(nearFieldSampler, inUV).a, 0.0001) * 0.02;
|
||||||
|
|
||||||
// read coc stored in the alpha channel
|
// read coc stored in the alpha channel
|
||||||
float coc = texture(farFieldSampler, inUV).a;
|
float coc = texture(farFieldSampler, inUV).a;
|
||||||
|
|
||||||
// transistion between out of focus and regular scene
|
// transistion between out of focus and regular scene
|
||||||
vec3 farColorBlurred = mix(sceneColor, farColor, clamp(coc, 0.0, 1.0));
|
vec3 farColorBlurred = mix(sceneColor, farColor, clamp(coc, 0.0, 1.0));
|
||||||
|
|
||||||
// smoother transistion between the normal scene and the "out of focus" portions
|
// 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));
|
farColorBlurred = mix(sceneColor, farColorBlurred, clamp(0.5 * coc + 1.0, 0.0, 1.0));
|
||||||
|
|
||||||
//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));
|
||||||
|
|
||||||
outColor = vec4(farColorBlurred, 1.0);
|
outColor = vec4(farColorBlurred, 1.0);
|
||||||
}
|
}
|
||||||
|
|
11
shaders/shadow.vert
Normal file
11
shaders/shadow.vert
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#version 460 core
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 inPosition;
|
||||||
|
|
||||||
|
layout(push_constant) uniform PushConstants {
|
||||||
|
mat4 mvp;
|
||||||
|
} pushConstants;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = pushConstants.mvp * vec4(inPosition, 1.0);
|
||||||
|
}
|
|
@ -239,7 +239,7 @@ int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
auto light = new Light();
|
auto light = new Light();
|
||||||
light->type = LightType::Directional;
|
light->type = LightType::Directional;
|
||||||
light->direction = glm::vec3(-0.2, -0.8, 0);
|
light->position = glm::vec3(66, 56, 25);
|
||||||
|
|
||||||
world.lights.push_back(light);
|
world.lights.push_back(light);
|
||||||
|
|
||||||
|
@ -362,7 +362,8 @@ int main(int argc, char* argv[]) {
|
||||||
if(SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS)
|
if(SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS)
|
||||||
io.MousePos = ImVec2(static_cast<float>(mouseX), static_cast<float>(mouseY));
|
io.MousePos = ImVec2(static_cast<float>(mouseX), static_cast<float>(mouseY));
|
||||||
|
|
||||||
ImGui::DragFloat3("Position", &camera.position[0], 0.1f);
|
ImGui::DragFloat3("Light Position", &world.lights[0]->position[0]);
|
||||||
|
ImGui::DragFloat3("Camera Position", &camera.position[0], 0.1f);
|
||||||
ImGui::DragFloat3("Target", &camera.target[0], 0.1f);
|
ImGui::DragFloat3("Target", &camera.target[0], 0.1f);
|
||||||
ImGui::DragFloat("Aperture", &camera.aperture, 0.01f, 0.0f, 1.0f);
|
ImGui::DragFloat("Aperture", &camera.aperture, 0.01f, 0.0f, 1.0f);
|
||||||
ImGui::DragFloat("Focus Distance", &camera.focusDistance);
|
ImGui::DragFloat("Focus Distance", &camera.focusDistance);
|
||||||
|
|
|
@ -26,6 +26,7 @@ Renderer::Renderer() {
|
||||||
createDescriptorPool();
|
createDescriptorPool();
|
||||||
createMaterialSetLayout();
|
createMaterialSetLayout();
|
||||||
|
|
||||||
|
shadowPass_ = new ShadowPass(*this);
|
||||||
worldPass_ = new WorldPass(*this);
|
worldPass_ = new WorldPass(*this);
|
||||||
postPass_ = new PostPass(*this);
|
postPass_ = new PostPass(*this);
|
||||||
dofPass_ = new DoFPass(*this);
|
dofPass_ = new DoFPass(*this);
|
||||||
|
@ -41,6 +42,7 @@ Renderer::~Renderer() {
|
||||||
delete dofPass_;
|
delete dofPass_;
|
||||||
delete postPass_;
|
delete postPass_;
|
||||||
delete worldPass_;
|
delete worldPass_;
|
||||||
|
delete shadowPass_;
|
||||||
|
|
||||||
vkDestroyDescriptorSetLayout(device_, materialSetLayout_, nullptr);
|
vkDestroyDescriptorSetLayout(device_, materialSetLayout_, nullptr);
|
||||||
|
|
||||||
|
@ -74,6 +76,8 @@ void Renderer::render(World& world, Camera& camera, RenderTarget* target) {
|
||||||
|
|
||||||
vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
||||||
|
|
||||||
|
shadowPass_->render(commandBuffer, world);
|
||||||
|
|
||||||
VkViewport viewport = {};
|
VkViewport viewport = {};
|
||||||
viewport.width = target->extent.width;
|
viewport.width = target->extent.width;
|
||||||
viewport.height = target->extent.height;
|
viewport.height = target->extent.height;
|
||||||
|
|
266
src/shadowpass.cpp
Normal file
266
src/shadowpass.cpp
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
#include "shadowpass.h"
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
|
#include "renderer.h"
|
||||||
|
#include "world.h"
|
||||||
|
#include "mesh.h"
|
||||||
|
#include "light.h"
|
||||||
|
|
||||||
|
ShadowPass::ShadowPass(Renderer& renderer) : renderer_(renderer) {
|
||||||
|
createRenderPass();
|
||||||
|
createFramebuffer();
|
||||||
|
createPipeline();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShadowPass::~ShadowPass() {
|
||||||
|
vkDestroyPipeline(renderer_.getDevice(), pipeline_, nullptr);
|
||||||
|
vkDestroyPipelineLayout(renderer_.getDevice(), pipelineLayout_, nullptr);
|
||||||
|
|
||||||
|
vkDestroySampler(renderer_.getDevice(), shadowSampler_, nullptr);
|
||||||
|
vkDestroyFramebuffer(renderer_.getDevice(), shadowFramebuffer_, nullptr);
|
||||||
|
vkDestroyImageView(renderer_.getDevice(), shadowImageView_, nullptr);
|
||||||
|
vkFreeMemory(renderer_.getDevice(), shadowMemory_, nullptr);
|
||||||
|
vkDestroyImage(renderer_.getDevice(), shadowImage_, nullptr);
|
||||||
|
|
||||||
|
vkDestroyRenderPass(renderer_.getDevice(), renderPass_, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShadowPass::render(VkCommandBuffer commandBuffer, World& world) {
|
||||||
|
VkViewport viewport = {};
|
||||||
|
viewport.width = 512;
|
||||||
|
viewport.height = 512;
|
||||||
|
viewport.maxDepth = 1.0f;
|
||||||
|
|
||||||
|
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
||||||
|
|
||||||
|
VkRect2D scissor = {};
|
||||||
|
scissor.extent.width = 512;
|
||||||
|
scissor.extent.height = 512;
|
||||||
|
|
||||||
|
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||||
|
|
||||||
|
VkClearValue clearColor = {};
|
||||||
|
clearColor.depthStencil.depth = 1.0f;
|
||||||
|
|
||||||
|
VkRenderPassBeginInfo renderPassBeginInfo = {};
|
||||||
|
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
|
renderPassBeginInfo.framebuffer = shadowFramebuffer_;
|
||||||
|
renderPassBeginInfo.renderPass = renderPass_;
|
||||||
|
renderPassBeginInfo.renderArea.extent.width = 512;
|
||||||
|
renderPassBeginInfo.renderArea.extent.height = 512;
|
||||||
|
renderPassBeginInfo.clearValueCount = 1;
|
||||||
|
renderPassBeginInfo.pClearValues = &clearColor;
|
||||||
|
|
||||||
|
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
|
||||||
|
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_);
|
||||||
|
|
||||||
|
glm::mat4 lightSpace = glm::mat4(1.0f);
|
||||||
|
//lightSpace = glm::perspective(glm::radians(75.0f), 1.0f, 0.1f, 100.0f);
|
||||||
|
lightSpace = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, 0.1f, 100.0f);
|
||||||
|
lightSpace *= glm::lookAt(world.lights[0]->position, glm::vec3(0), glm::vec3(0, -1, 0));
|
||||||
|
|
||||||
|
world.lights[0]->matrix = lightSpace;
|
||||||
|
|
||||||
|
for(const auto& mesh : world.meshes) {
|
||||||
|
glm::mat4 mvp = world.lights[0]->matrix;
|
||||||
|
mvp = glm::translate(mvp, mesh->position);
|
||||||
|
|
||||||
|
vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &mvp);
|
||||||
|
|
||||||
|
VkDeviceSize offsets[] = {0};
|
||||||
|
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &mesh->vertexBuffer, offsets);
|
||||||
|
vkCmdBindIndexBuffer(commandBuffer, mesh->indexBuffer, 0, VK_INDEX_TYPE_UINT32);
|
||||||
|
|
||||||
|
vkCmdDrawIndexed(commandBuffer, mesh->indices.size(), 1, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vkCmdEndRenderPass(commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShadowPass::createRenderPass() {
|
||||||
|
VkAttachmentDescription depthAttachment = {};
|
||||||
|
depthAttachment.format = VK_FORMAT_D32_SFLOAT;
|
||||||
|
depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
|
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
|
depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
depthAttachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
|
||||||
|
VkAttachmentReference depthAttachmentRef = {};
|
||||||
|
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
|
|
||||||
|
VkSubpassDescription subpass = {};
|
||||||
|
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||||
|
subpass.pDepthStencilAttachment = &depthAttachmentRef;
|
||||||
|
|
||||||
|
VkRenderPassCreateInfo renderPassInfo = {};
|
||||||
|
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||||
|
renderPassInfo.attachmentCount = 1;
|
||||||
|
renderPassInfo.pAttachments = &depthAttachment;
|
||||||
|
renderPassInfo.subpassCount = 1;
|
||||||
|
renderPassInfo.pSubpasses = &subpass;
|
||||||
|
|
||||||
|
vkCreateRenderPass(renderer_.getDevice(), &renderPassInfo, nullptr, &renderPass_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShadowPass::createFramebuffer() {
|
||||||
|
VkImageCreateInfo imageCreateInfo = {};
|
||||||
|
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||||
|
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||||
|
imageCreateInfo.format = VK_FORMAT_D32_SFLOAT;
|
||||||
|
imageCreateInfo.extent.width = 512;
|
||||||
|
imageCreateInfo.extent.height = 512;
|
||||||
|
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_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||||
|
|
||||||
|
vkCreateImage(renderer_.getDevice(), &imageCreateInfo, nullptr, &shadowImage_);
|
||||||
|
|
||||||
|
VkMemoryRequirements memoryRequirements = {};
|
||||||
|
vkGetImageMemoryRequirements(renderer_.getDevice(), shadowImage_, &memoryRequirements);
|
||||||
|
|
||||||
|
VkMemoryAllocateInfo allocateInfo = {};
|
||||||
|
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
|
allocateInfo.allocationSize = memoryRequirements.size;
|
||||||
|
allocateInfo.memoryTypeIndex = renderer_.findMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
|
|
||||||
|
vkAllocateMemory(renderer_.getDevice(), &allocateInfo, nullptr, &shadowMemory_);
|
||||||
|
vkBindImageMemory(renderer_.getDevice(), shadowImage_, shadowMemory_, 0);
|
||||||
|
|
||||||
|
VkImageViewCreateInfo createInfo = {};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
createInfo.image = shadowImage_;
|
||||||
|
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
createInfo.format = VK_FORMAT_D32_SFLOAT;
|
||||||
|
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
|
createInfo.subresourceRange.levelCount = 1;
|
||||||
|
createInfo.subresourceRange.layerCount = 1;
|
||||||
|
|
||||||
|
vkCreateImageView(renderer_.getDevice(), &createInfo, nullptr, &shadowImageView_);
|
||||||
|
|
||||||
|
VkFramebufferCreateInfo framebufferInfo = {};
|
||||||
|
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||||
|
framebufferInfo.renderPass = renderPass_;
|
||||||
|
framebufferInfo.attachmentCount = 1;
|
||||||
|
framebufferInfo.pAttachments = &shadowImageView_;
|
||||||
|
framebufferInfo.width = 512;
|
||||||
|
framebufferInfo.height = 512;
|
||||||
|
framebufferInfo.layers = 1;
|
||||||
|
|
||||||
|
vkCreateFramebuffer(renderer_.getDevice(), &framebufferInfo, nullptr, &shadowFramebuffer_);
|
||||||
|
|
||||||
|
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_FLOAT_OPAQUE_BLACK;
|
||||||
|
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||||
|
|
||||||
|
vkCreateSampler(renderer_.getDevice(), &samplerInfo, nullptr, &shadowSampler_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShadowPass::createPipeline() {
|
||||||
|
VkShaderModule vertShaderModule = renderer_.createShader("shaders/shadow.vert.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";
|
||||||
|
|
||||||
|
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.lineWidth = 1.0f;
|
||||||
|
rasterizer.cullMode = VK_CULL_MODE_FRONT_BIT;
|
||||||
|
rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
||||||
|
rasterizer.depthBiasEnable = VK_TRUE;
|
||||||
|
rasterizer.depthBiasConstantFactor = 1.25f;
|
||||||
|
rasterizer.depthBiasSlopeFactor = 1.75f;
|
||||||
|
|
||||||
|
VkPipelineMultisampleStateCreateInfo multisampling = {};
|
||||||
|
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||||
|
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
|
||||||
|
VkPipelineColorBlendStateCreateInfo colorBlending = {};
|
||||||
|
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||||
|
|
||||||
|
VkPipelineDepthStencilStateCreateInfo depthState = {};
|
||||||
|
depthState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||||
|
depthState.depthTestEnable = VK_TRUE;
|
||||||
|
depthState.depthWriteEnable = VK_TRUE;
|
||||||
|
depthState.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
|
||||||
|
|
||||||
|
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 = 1;
|
||||||
|
pipelineInfo.pStages = &vertShaderStageInfo;
|
||||||
|
pipelineInfo.pVertexInputState = &vertexInputInfo;
|
||||||
|
pipelineInfo.pInputAssemblyState = &inputAssembly;
|
||||||
|
pipelineInfo.pViewportState = &viewportState;
|
||||||
|
pipelineInfo.pRasterizationState = &rasterizer;
|
||||||
|
pipelineInfo.pMultisampleState = &multisampling;
|
||||||
|
pipelineInfo.pColorBlendState = &colorBlending;
|
||||||
|
pipelineInfo.pDepthStencilState = &depthState;
|
||||||
|
pipelineInfo.pDynamicState = &dynamicState;
|
||||||
|
pipelineInfo.layout = pipelineLayout_;
|
||||||
|
pipelineInfo.renderPass = renderPass_;
|
||||||
|
|
||||||
|
vkCreateGraphicsPipelines(renderer_.getDevice(), nullptr, 1, &pipelineInfo, nullptr, &pipeline_);
|
||||||
|
|
||||||
|
vkDestroyShaderModule(renderer_.getDevice(), vertShaderModule, nullptr);
|
||||||
|
}
|
|
@ -41,7 +41,7 @@ void WorldPass::render(VkCommandBuffer commandBuffer, World& world, Camera& came
|
||||||
|
|
||||||
for(const auto& light : world.lights) {
|
for(const auto& light : world.lights) {
|
||||||
data->position = glm::vec4(light->position, (int)light->type);
|
data->position = glm::vec4(light->position, (int)light->type);
|
||||||
data->direction = glm::vec4(light->direction, 0.0);
|
data->direction = glm::vec4(glm::normalize(glm::vec3(0) - light->position), 0.0);
|
||||||
data->color = light->color;
|
data->color = light->color;
|
||||||
|
|
||||||
data++;
|
data++;
|
||||||
|
@ -55,12 +55,13 @@ void WorldPass::render(VkCommandBuffer commandBuffer, World& world, Camera& came
|
||||||
for(const auto& mesh : world.meshes) {
|
for(const auto& mesh : world.meshes) {
|
||||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 1, 1, &mesh->material->set, 0, nullptr);
|
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 1, 1, &mesh->material->set, 0, nullptr);
|
||||||
|
|
||||||
glm::mat4 mvp;
|
glm::mat4 vp;
|
||||||
mvp = glm::perspective(glm::radians(75.0f), (float)target->extent.width / target->extent.height, camera.near, camera.far);
|
vp = glm::perspective(glm::radians(75.0f), (float)target->extent.width / target->extent.height, camera.near, camera.far);
|
||||||
mvp *= glm::lookAt(camera.position, camera.target, glm::vec3(0, -1, 0));
|
vp *= glm::lookAt(camera.position, camera.target, glm::vec3(0, -1, 0));
|
||||||
mvp = glm::translate(mvp, mesh->position);
|
|
||||||
|
|
||||||
vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &mvp);
|
vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &vp);
|
||||||
|
|
||||||
|
vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT, sizeof(glm::mat4), sizeof(glm::mat4), &world.lights[0]->matrix);
|
||||||
|
|
||||||
VkDeviceSize offsets[] = {0};
|
VkDeviceSize offsets[] = {0};
|
||||||
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &mesh->vertexBuffer, offsets);
|
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &mesh->vertexBuffer, offsets);
|
||||||
|
@ -144,10 +145,21 @@ void WorldPass::createDescriptorSetLayout() {
|
||||||
lightBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
lightBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
lightBufferBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
lightBufferBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutBinding shadowBinding = {};
|
||||||
|
shadowBinding.descriptorCount = 1;
|
||||||
|
shadowBinding.binding = 1;
|
||||||
|
shadowBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
shadowBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
|
||||||
|
const std::array<VkDescriptorSetLayoutBinding, 2> bindings = {
|
||||||
|
lightBufferBinding,
|
||||||
|
shadowBinding
|
||||||
|
};
|
||||||
|
|
||||||
VkDescriptorSetLayoutCreateInfo createInfo = {};
|
VkDescriptorSetLayoutCreateInfo createInfo = {};
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
createInfo.bindingCount = 1;
|
createInfo.bindingCount = bindings.size();
|
||||||
createInfo.pBindings = &lightBufferBinding;
|
createInfo.pBindings = bindings.data();
|
||||||
|
|
||||||
vkCreateDescriptorSetLayout(renderer_.getDevice(), &createInfo, nullptr, &setLayout_);
|
vkCreateDescriptorSetLayout(renderer_.getDevice(), &createInfo, nullptr, &setLayout_);
|
||||||
}
|
}
|
||||||
|
@ -245,7 +257,7 @@ void WorldPass::createPipeline() {
|
||||||
dynamicState.pDynamicStates = dynamicStates.data();
|
dynamicState.pDynamicStates = dynamicStates.data();
|
||||||
|
|
||||||
VkPushConstantRange mvpPushConstant = {};
|
VkPushConstantRange mvpPushConstant = {};
|
||||||
mvpPushConstant.size = sizeof(glm::mat4);
|
mvpPushConstant.size = sizeof(glm::mat4) * 2;
|
||||||
mvpPushConstant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
mvpPushConstant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
|
||||||
const std::array<VkDescriptorSetLayout, 2> setLayouts = {
|
const std::array<VkDescriptorSetLayout, 2> setLayouts = {
|
||||||
|
@ -317,14 +329,32 @@ void WorldPass::createDescriptorSet() {
|
||||||
bufferInfo.buffer = lightBuffer_;
|
bufferInfo.buffer = lightBuffer_;
|
||||||
bufferInfo.range = sizeof(float) * (4 + 4 + 3) * 32;
|
bufferInfo.range = sizeof(float) * (4 + 4 + 3) * 32;
|
||||||
|
|
||||||
VkWriteDescriptorSet descriptorWrite = {};
|
VkDescriptorImageInfo imageInfo = {};
|
||||||
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
descriptorWrite.descriptorCount = 1;
|
imageInfo.imageView = renderer_.getShadowPass().getImageView();
|
||||||
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
imageInfo.sampler = renderer_.getShadowPass().getSampler();
|
||||||
descriptorWrite.dstSet = descriptorSet_;
|
|
||||||
descriptorWrite.pBufferInfo = &bufferInfo;
|
|
||||||
|
|
||||||
vkUpdateDescriptorSets(renderer_.getDevice(), 1, &descriptorWrite, 0, nullptr);
|
VkWriteDescriptorSet bufferDescriptorWrite = {};
|
||||||
|
bufferDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
bufferDescriptorWrite.descriptorCount = 1;
|
||||||
|
bufferDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
|
bufferDescriptorWrite.dstSet = descriptorSet_;
|
||||||
|
bufferDescriptorWrite.pBufferInfo = &bufferInfo;
|
||||||
|
|
||||||
|
VkWriteDescriptorSet shadowDescriptorWrite = {};
|
||||||
|
shadowDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
shadowDescriptorWrite.descriptorCount = 1;
|
||||||
|
shadowDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
shadowDescriptorWrite.dstBinding = 1;
|
||||||
|
shadowDescriptorWrite.dstSet = descriptorSet_;
|
||||||
|
shadowDescriptorWrite.pImageInfo = &imageInfo;
|
||||||
|
|
||||||
|
const std::array<VkWriteDescriptorSet, 2> descriptorWrites = {
|
||||||
|
bufferDescriptorWrite,
|
||||||
|
shadowDescriptorWrite
|
||||||
|
};
|
||||||
|
|
||||||
|
vkUpdateDescriptorSets(renderer_.getDevice(), descriptorWrites.size(), descriptorWrites.data(), 0, nullptr);
|
||||||
|
|
||||||
float* data;
|
float* data;
|
||||||
vkMapMemory(renderer_.getDevice(), lightMemory_, 0, sizeof(float) * (4 + 4 + 3) * 32, 0, reinterpret_cast<void**>(&data));
|
vkMapMemory(renderer_.getDevice(), lightMemory_, 0, sizeof(float) * (4 + 4 + 3) * 32, 0, reinterpret_cast<void**>(&data));
|
||||||
|
|
Reference in a new issue