Fix shadow mapping for alpha-clipped meshes

This commit is contained in:
bailehuni 2024-03-28 00:14:09 +00:00
parent dfd892b146
commit 716dc8f5f0
9 changed files with 34 additions and 13 deletions

View File

@ -34,6 +34,10 @@ float GGXDist(float alpha_2, float N_dot_H) {
void main() {
const vec4 albedo_alpha = texture(materialSetAlbedoSampler, fragUV);
if (albedo_alpha.a < 0.9) discard; // discard fragments without alpha = 1.0
const vec3 albedo = albedo_alpha.xyz;
const vec3 occlusion_roughness_metallic = vec3(texture(materialSetOcclusionRoughnessMetallic, fragUV));
const float ao = occlusion_roughness_metallic.r;
const float roughness = occlusion_roughness_metallic.g;
@ -52,7 +56,6 @@ void main() {
const vec3 emission = vec3(0.0, 0.0, 0.0);
const vec3 albedo = vec3(texture(materialSetAlbedoSampler, fragUV));
const vec3 N = GetNormal();
const vec3 V = normalize(fragViewPosTangentSpace - fragPosTangentSpace);
@ -91,19 +94,19 @@ void main() {
projCoords.y = projCoords.y * 0.5 + 0.5;
//float closestDepth = texture(globalSetShadowmap, projCoords.xy).r;
const float currentDepth = max(projCoords.z, 0.0);
const float bias = max(0.02 * (1.0 - L_dot_N), 0.005);
const float bias = max(0.01 * (1.0 - L_dot_N), 0.005);
//float shadow = currentDepth - bias > closestDepth ? 0.0 : 1.0;
float shadow = 0.0;
vec2 texelSize = 1.0 / textureSize(globalSetShadowmap, 0);
for(int x = -1; x <= 1; ++x)
for(int x = -2; x <= 2; ++x)
{
for(int y = -1; y <= 1; ++y)
for(int y = -2; y <= 2; ++y)
{
float pcfDepth = texture(globalSetShadowmap, projCoords.xy + vec2(x, y) * texelSize).r;
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
}
}
shadow /= 9.0;
shadow /= 25.0;
lighting *= (1.0 - shadow);

View File

@ -1,5 +1,9 @@
#version 450
layout(set = 2, binding = 0) uniform sampler2D materialSetAlbedoSampler;
layout(location = 0) in vec2 fragUV;
void main() {
// empty fragment shader
if (texture(materialSetAlbedoSampler, fragUV).a < 1.0) discard;
}

View File

@ -10,8 +10,12 @@ layout( push_constant ) uniform Constants {
} constants;
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec2 inUV;
layout(location = 0) out vec2 fragUV;
void main() {
fragUV = inUV;
gl_Position = globalSetUniformBuffer.lightSpaceMatrix * constants.model * vec4(inPosition, 1.0);
//gl_Position.y *= -1.0;
}

View File

@ -72,7 +72,7 @@ static constexpr uint32_t FRAMES_IN_FLIGHT = 2; // This improved FPS by 5x
static constexpr size_t PUSH_CONSTANT_MAX_SIZE = 128; // bytes
static constexpr VkIndexType INDEX_TYPE = VK_INDEX_TYPE_UINT32;
static constexpr int kShadowmapSize = 2048;
static constexpr int kShadowmapSize = 4096;
// structures and enums

View File

@ -195,6 +195,7 @@ Renderer::Renderer(Application& app, gfx::GraphicsSettings settings) : Applicati
gfx::VertexFormat shadowVertexFormat{};
shadowVertexFormat.stride = sizeof(float) * 12; // using the full meshes so a lot of data is skipped
shadowVertexFormat.attribute_descriptions.emplace_back(0, gfx::VertexAttribFormat::kFloat3, 0); // position
shadowVertexFormat.attribute_descriptions.emplace_back(1, gfx::VertexAttribFormat::kFloat2, sizeof(float) * 10); // uv
gfx::PipelineInfo shadowPipelineInfo{};
shadowPipelineInfo.vert_shader_path = GetResourcePath("engine/shaders/shadow.vert");
shadowPipelineInfo.frag_shader_path = GetResourcePath("engine/shaders/shadow.frag");
@ -205,6 +206,8 @@ Renderer::Renderer(Application& app, gfx::GraphicsSettings settings) : Applicati
shadowPipelineInfo.line_primitives = false;
shadowPipelineInfo.depth_attachment_only = true;
shadowPipelineInfo.descriptor_set_layouts.emplace_back(GetGlobalSetLayout());
shadowPipelineInfo.descriptor_set_layouts.emplace_back(GetFrameSetLayout());
shadowPipelineInfo.descriptor_set_layouts.emplace_back(GetMaterialSetLayout());
shadow_pipeline = device_->CreatePipeline(shadowPipelineInfo);
// shadow map image and sampler
@ -212,7 +215,7 @@ Renderer::Renderer(Application& app, gfx::GraphicsSettings settings) : Applicati
gfx::SamplerInfo sampler_info{};
sampler_info.magnify = gfx::Filter::kLinear;
sampler_info.minify = gfx::Filter::kLinear;
sampler_info.mipmap = gfx::Filter::kLinear; // trilinear is apparently good for shadow maps
sampler_info.mipmap = gfx::Filter::kNearest; // bilinear is apparently good for shadow maps, mips aren't used anyway
sampler_info.wrap_u = gfx::WrapMode::kClampToBorder; // sampler reads 1.0 out of bounds which ensures no shadowing there
sampler_info.wrap_v = gfx::WrapMode::kClampToBorder;
sampler_info.wrap_w = gfx::WrapMode::kClampToBorder;
@ -276,6 +279,7 @@ void Renderer::Render(const RenderList* static_list, const RenderList* dynamic_l
if (!static_list->empty()) {
for (const auto& entry : *static_list) {
device_->CmdPushConstants(shadow_draw, shadow_pipeline, 0, sizeof(entry.model_matrix), &entry.model_matrix);
device_->CmdBindDescriptorSet(shadow_draw, shadow_pipeline, entry.material_set, 2);
device_->CmdBindVertexBuffer(shadow_draw, 0, entry.vertex_buffer);
device_->CmdBindIndexBuffer(shadow_draw, entry.index_buffer);
device_->CmdDrawIndexed(shadow_draw, entry.index_count, 1, 0, 0, 0);

Binary file not shown.

BIN
test/res/models/tree.glb Normal file

Binary file not shown.

View File

@ -14,6 +14,7 @@
#include "scene_manager.h"
#include "window.h"
#include <systems/collisions.h>
#include <components/mesh_renderable.h>
CameraControllerSystem::CameraControllerSystem(engine::Scene* scene)
: System(scene, {typeid(engine::TransformComponent).hash_code(), typeid(CameraControllerComponent).hash_code()})
@ -212,6 +213,8 @@ void CameraControllerSystem::OnUpdate(float ts)
LOG_INFO("Ray direction: {} {} {}", ray.direction.x, ray.direction.y, ray.direction.z);
LOG_INFO("Hit Entity: {}", scene_->GetComponent<engine::TransformComponent>(cast.hit_entity)->tag);
c->perm_lines.emplace_back(ray.origin, cast.location, glm::vec3{0.0f, 0.0f, 1.0f});
scene_->GetComponent<engine::MeshRenderableComponent>(cast.hit_entity)->visible ^= true;
scene_->GetSystem<engine::MeshRenderSystem>()->RebuildStaticRenderList();
}
}

View File

@ -48,7 +48,7 @@ void PlayGame(GameSettings settings)
engine::gfx::GraphicsSettings graphics_settings{};
graphics_settings.enable_validation = settings.enable_validation;
graphics_settings.vsync = true;
graphics_settings.wait_for_present = false;
graphics_settings.wait_for_present = true;
graphics_settings.msaa_level = engine::gfx::MSAALevel::kOff;
graphics_settings.enable_anisotropy = true;
@ -141,6 +141,9 @@ void PlayGame(GameSettings settings)
main_scene->GetPosition(teapot).y += 5.0f;
main_scene->GetPosition(teapot).x -= 5.0f;
main_scene->GetScale(teapot) *= 5.0f;
engine::Entity tree = engine::util::LoadGLTF(*main_scene, app.GetResourcePath("models/tree.glb"), true);
main_scene->GetPosition(tree) = glm::vec3{-5.0f, -5.0f, 0.0f};
}
start_scene->GetSystem<CameraControllerSystem>()->next_scene_ = main_scene;