From d5dcb3ddeec53c2b2023d8d479d143b0312a14e5 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Thu, 8 Nov 2018 13:51:08 -0500 Subject: [PATCH] Make PCF filtering configurable, improve shader performance --- data/graphics_presets.cfg | 3 +++ include/renderer.h | 2 +- shaders/mesh.frag | 17 +++++++++++------ src/main.cpp | 1 + src/worldpass.cpp | 33 +++++++++++++++++++++++++-------- 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/data/graphics_presets.cfg b/data/graphics_presets.cfg index 8a9d870..d414a22 100644 --- a/data/graphics_presets.cfg +++ b/data/graphics_presets.cfg @@ -1,11 +1,14 @@ [Low] shadowResolution=128 dofDownscale=8 +filterPCF=0 [Medium] shadowResolution=256 dofDownscale=4 +filterPCF=1 [High] shadowResolution=512 dofDownscale=2 +filterPCF=1 diff --git a/include/renderer.h b/include/renderer.h index 8f3e730..e6abba0 100644 --- a/include/renderer.h +++ b/include/renderer.h @@ -70,7 +70,7 @@ struct RenderTarget { struct GraphicsConfig { int shadowResolution, dofDownscale; - bool vsync = true; + bool vsync = true, filterPCF; }; class World; diff --git a/shaders/mesh.frag b/shaders/mesh.frag index 3dba3fe..29d914f 100644 --- a/shaders/mesh.frag +++ b/shaders/mesh.frag @@ -8,7 +8,7 @@ layout(location = 3) in vec2 inUV; layout(location = 0) out vec4 outColor; struct Light { - vec4 position, direction; + vec4 position; vec3 color; }; @@ -19,6 +19,8 @@ layout(set = 0, binding = 0) uniform Lights { layout(set = 0, binding = 1) uniform sampler2D shadowSampler; layout(set = 1, binding = 0) uniform sampler2D albedoSampler; +layout(constant_id = 0) const int shadowFilterPCF = 1; + float textureProj(vec4 P, vec2 off) { const vec4 shadowCoord = P / P.w; // perspective divide @@ -54,16 +56,19 @@ float filterPCF(vec4 sc) { void main() { vec3 diffuse = vec3(0); for(int i = 0; i < 32; i++) { - const vec3 norm = normalize(inNormal); - vec3 lightDir = vec3(0); if(lights[i].position.w == 0) + continue; + else if(lights[i].position.w == 1) lightDir = normalize(lights[i].position.xyz - inFragPos); - else - lightDir = normalize(-lights[i].direction.xyz); + else if(lights[i].position.w == 2) + lightDir = normalize(-lights[i].position.xyz); + + const vec3 norm = normalize(inNormal); const float diff = max(dot(norm, lightDir), 0.0); - diffuse += vec3(diff) * lights[i].color * filterPCF(inShadowPos / inShadowPos.w); + const float shadow = shadowFilterPCF == 1 ? filterPCF(inShadowPos / inShadowPos.w) : textureProj(inShadowPos / inShadowPos.w, vec2(0, 0)); + diffuse += vec3(diff) * lights[i].color * shadow; } outColor = vec4(vec3(0.1) + diffuse * texture(albedoSampler, inUV).rgb, 1.0); diff --git a/src/main.cpp b/src/main.cpp index a5b856e..6e9c9ce 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -61,6 +61,7 @@ void loadGraphicsConfig() { graphicsConfig.shadowResolution = toInt(config.get(currentGraphicsPreset.c_str(), "shadowResolution")); graphicsConfig.dofDownscale = toInt(config.get(currentGraphicsPreset.c_str(), "dofDownscale")); + graphicsConfig.filterPCF = toInt(config.get(currentGraphicsPreset.c_str(), "filterPCF")); } void readConfig() { diff --git a/src/worldpass.cpp b/src/worldpass.cpp index 41c60bd..6f9cdff 100644 --- a/src/worldpass.cpp +++ b/src/worldpass.cpp @@ -32,16 +32,21 @@ WorldPass::~WorldPass() { void WorldPass::render(VkCommandBuffer commandBuffer, World& world, Camera& camera, RenderTarget* target) { struct ShaderLight { - glm::vec4 position, direction; + glm::vec4 position; glm::vec3 color; }; ShaderLight* data; - vkMapMemory(renderer_.getDevice(), lightMemory_, 0, sizeof(float) * (4 + 4 + 3) * 32, 0, reinterpret_cast(&data)); + vkMapMemory(renderer_.getDevice(), lightMemory_, 0, sizeof(float) * (4 + 3) * 32, 0, reinterpret_cast(&data)); for(const auto& light : world.lights) { - data->position = glm::vec4(light->position, (int)light->type); - data->direction = glm::vec4(glm::normalize(glm::vec3(0) - light->position), 0.0); + glm::vec3 position; + if(light->type == LightType::Point) + position = light->position; + else + position = glm::normalize(glm::vec3(0) - light->position); + + data->position = glm::vec4(position, ((int)light->type) + 1); data->color = light->color; data++; @@ -174,11 +179,23 @@ void WorldPass::createPipeline() { vertShaderStageInfo.module = vertShaderModule; vertShaderStageInfo.pName = "main"; + VkSpecializationMapEntry mapEntry = {}; + mapEntry.size = sizeof(int); + + VkSpecializationInfo specializationInfo = {}; + specializationInfo.mapEntryCount = 1; + specializationInfo.pMapEntries = &mapEntry; + specializationInfo.dataSize = sizeof(int); + + int shadowFilterPCF = renderer_.getConfig().filterPCF; + specializationInfo.pData = &shadowFilterPCF; + 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"; + fragShaderStageInfo.pSpecializationInfo = &specializationInfo; const std::array shaderStages = {vertShaderStageInfo, fragShaderStageInfo}; @@ -298,7 +315,7 @@ void WorldPass::createPipeline() { void WorldPass::createUniformBuffer() { VkBufferCreateInfo bufferInfo = {}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = sizeof(float) * (4 + 4 + 3) * 32; + bufferInfo.size = sizeof(float) * (4 + 3) * 32; bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; @@ -327,7 +344,7 @@ void WorldPass::createDescriptorSet() { VkDescriptorBufferInfo bufferInfo = {}; bufferInfo.buffer = lightBuffer_; - bufferInfo.range = sizeof(float) * (4 + 4 + 3) * 32; + bufferInfo.range = sizeof(float) * (4 + 3) * 32; VkDescriptorImageInfo imageInfo = {}; imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -357,9 +374,9 @@ void WorldPass::createDescriptorSet() { vkUpdateDescriptorSets(renderer_.getDevice(), descriptorWrites.size(), descriptorWrites.data(), 0, nullptr); float* data; - vkMapMemory(renderer_.getDevice(), lightMemory_, 0, sizeof(float) * (4 + 4 + 3) * 32, 0, reinterpret_cast(&data)); + vkMapMemory(renderer_.getDevice(), lightMemory_, 0, sizeof(float) * (4 + 3) * 32, 0, reinterpret_cast(&data)); - for(uint32_t i = 0; i < (4 + 4 + 3) * 32; i++) + for(uint32_t i = 0; i < (4 + 3) * 32; i++) data[i] = 0.0f; vkUnmapMemory(renderer_.getDevice(), lightMemory_);