Archived
1
Fork 0

Make PCF filtering configurable, improve shader performance

This commit is contained in:
Joshua Goins 2018-11-08 13:51:08 -05:00
parent 73789e58aa
commit d5dcb3ddee
5 changed files with 41 additions and 15 deletions

View file

@ -1,11 +1,14 @@
[Low] [Low]
shadowResolution=128 shadowResolution=128
dofDownscale=8 dofDownscale=8
filterPCF=0
[Medium] [Medium]
shadowResolution=256 shadowResolution=256
dofDownscale=4 dofDownscale=4
filterPCF=1
[High] [High]
shadowResolution=512 shadowResolution=512
dofDownscale=2 dofDownscale=2
filterPCF=1

View file

@ -70,7 +70,7 @@ struct RenderTarget {
struct GraphicsConfig { struct GraphicsConfig {
int shadowResolution, dofDownscale; int shadowResolution, dofDownscale;
bool vsync = true; bool vsync = true, filterPCF;
}; };
class World; class World;

View file

@ -8,7 +8,7 @@ layout(location = 3) in vec2 inUV;
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 outColor;
struct Light { struct Light {
vec4 position, direction; vec4 position;
vec3 color; vec3 color;
}; };
@ -19,6 +19,8 @@ layout(set = 0, binding = 0) uniform Lights {
layout(set = 0, binding = 1) uniform sampler2D shadowSampler; layout(set = 0, binding = 1) uniform sampler2D shadowSampler;
layout(set = 1, binding = 0) uniform sampler2D albedoSampler; layout(set = 1, binding = 0) uniform sampler2D albedoSampler;
layout(constant_id = 0) const int shadowFilterPCF = 1;
float textureProj(vec4 P, vec2 off) { float textureProj(vec4 P, vec2 off) {
const vec4 shadowCoord = P / P.w; // perspective divide const vec4 shadowCoord = P / P.w; // perspective divide
@ -54,16 +56,19 @@ float filterPCF(vec4 sc) {
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++) {
const vec3 norm = normalize(inNormal);
vec3 lightDir = vec3(0); vec3 lightDir = vec3(0);
if(lights[i].position.w == 0) if(lights[i].position.w == 0)
continue;
else if(lights[i].position.w == 1)
lightDir = normalize(lights[i].position.xyz - inFragPos); lightDir = normalize(lights[i].position.xyz - inFragPos);
else else if(lights[i].position.w == 2)
lightDir = normalize(-lights[i].direction.xyz); lightDir = normalize(-lights[i].position.xyz);
const vec3 norm = normalize(inNormal);
const float diff = max(dot(norm, lightDir), 0.0); 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); outColor = vec4(vec3(0.1) + diffuse * texture(albedoSampler, inUV).rgb, 1.0);

View file

@ -61,6 +61,7 @@ void loadGraphicsConfig() {
graphicsConfig.shadowResolution = toInt(config.get(currentGraphicsPreset.c_str(), "shadowResolution")); graphicsConfig.shadowResolution = toInt(config.get(currentGraphicsPreset.c_str(), "shadowResolution"));
graphicsConfig.dofDownscale = toInt(config.get(currentGraphicsPreset.c_str(), "dofDownscale")); graphicsConfig.dofDownscale = toInt(config.get(currentGraphicsPreset.c_str(), "dofDownscale"));
graphicsConfig.filterPCF = toInt(config.get(currentGraphicsPreset.c_str(), "filterPCF"));
} }
void readConfig() { void readConfig() {

View file

@ -32,16 +32,21 @@ WorldPass::~WorldPass() {
void WorldPass::render(VkCommandBuffer commandBuffer, World& world, Camera& camera, RenderTarget* target) { void WorldPass::render(VkCommandBuffer commandBuffer, World& world, Camera& camera, RenderTarget* target) {
struct ShaderLight { struct ShaderLight {
glm::vec4 position, direction; glm::vec4 position;
glm::vec3 color; glm::vec3 color;
}; };
ShaderLight* data; ShaderLight* 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 + 3) * 32, 0, reinterpret_cast<void**>(&data));
for(const auto& light : world.lights) { for(const auto& light : world.lights) {
data->position = glm::vec4(light->position, (int)light->type); glm::vec3 position;
data->direction = glm::vec4(glm::normalize(glm::vec3(0) - light->position), 0.0); 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->color = light->color;
data++; data++;
@ -174,11 +179,23 @@ void WorldPass::createPipeline() {
vertShaderStageInfo.module = vertShaderModule; vertShaderStageInfo.module = vertShaderModule;
vertShaderStageInfo.pName = "main"; 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 = {}; VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
fragShaderStageInfo.module = fragShaderModule; fragShaderStageInfo.module = fragShaderModule;
fragShaderStageInfo.pName = "main"; fragShaderStageInfo.pName = "main";
fragShaderStageInfo.pSpecializationInfo = &specializationInfo;
const std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages = {vertShaderStageInfo, fragShaderStageInfo}; const std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages = {vertShaderStageInfo, fragShaderStageInfo};
@ -298,7 +315,7 @@ void WorldPass::createPipeline() {
void WorldPass::createUniformBuffer() { void WorldPass::createUniformBuffer() {
VkBufferCreateInfo bufferInfo = {}; VkBufferCreateInfo bufferInfo = {};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; 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.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
@ -327,7 +344,7 @@ void WorldPass::createDescriptorSet() {
VkDescriptorBufferInfo bufferInfo = {}; VkDescriptorBufferInfo bufferInfo = {};
bufferInfo.buffer = lightBuffer_; bufferInfo.buffer = lightBuffer_;
bufferInfo.range = sizeof(float) * (4 + 4 + 3) * 32; bufferInfo.range = sizeof(float) * (4 + 3) * 32;
VkDescriptorImageInfo imageInfo = {}; VkDescriptorImageInfo imageInfo = {};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 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); 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 + 3) * 32, 0, reinterpret_cast<void**>(&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; data[i] = 0.0f;
vkUnmapMemory(renderer_.getDevice(), lightMemory_); vkUnmapMemory(renderer_.getDevice(), lightMemory_);