Make PCF filtering configurable, improve shader performance
This commit is contained in:
parent
73789e58aa
commit
d5dcb3ddee
5 changed files with 41 additions and 15 deletions
|
@ -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
|
||||
|
|
|
@ -70,7 +70,7 @@ struct RenderTarget {
|
|||
|
||||
struct GraphicsConfig {
|
||||
int shadowResolution, dofDownscale;
|
||||
bool vsync = true;
|
||||
bool vsync = true, filterPCF;
|
||||
};
|
||||
|
||||
class World;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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<void**>(&data));
|
||||
vkMapMemory(renderer_.getDevice(), lightMemory_, 0, sizeof(float) * (4 + 3) * 32, 0, reinterpret_cast<void**>(&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<VkPipelineShaderStageCreateInfo, 2> 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<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;
|
||||
|
||||
vkUnmapMemory(renderer_.getDevice(), lightMemory_);
|
||||
|
|
Reference in a new issue