diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp index c2407f8ab..ccdb46ac7 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp @@ -820,7 +820,7 @@ VkSampler* HelperResourcesVulkan::GetStaticSamplers() RenderToolsVulkan::ZeroStruct(createInfo, VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO); createInfo.mipLodBias = 0.0f; createInfo.minLod = 0.0f; - createInfo.maxLod = MAX_float; + createInfo.maxLod = 1000.0f; createInfo.maxAnisotropy = 1.0f; createInfo.anisotropyEnable = VK_FALSE; createInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; diff --git a/Source/Engine/Level/Actors/DirectionalLight.cpp b/Source/Engine/Level/Actors/DirectionalLight.cpp index d828b619d..d641dfc77 100644 --- a/Source/Engine/Level/Actors/DirectionalLight.cpp +++ b/Source/Engine/Level/Actors/DirectionalLight.cpp @@ -10,6 +10,8 @@ DirectionalLight::DirectionalLight(const SpawnParams& params) : LightWithShadow(params) { + ShadowsDepthBias = 0.002f; + _drawNoCulling = 1; Brightness = 8.0f; } diff --git a/Source/Engine/Level/Actors/Light.h b/Source/Engine/Level/Actors/Light.h index 0e2a441db..a92be15af 100644 --- a/Source/Engine/Level/Actors/Light.h +++ b/Source/Engine/Level/Actors/Light.h @@ -151,7 +151,7 @@ public: /// The depth bias used for shadow map comparison. /// API_FIELD(Attributes="EditorOrder(95), EditorDisplay(\"Shadow\", \"Depth Bias\"), Limit(0.0f, 10.0f, 0.0001f)") - float ShadowsDepthBias = 0.005f; + float ShadowsDepthBias = 0.05f; /// /// A factor specifying the offset to add to the calculated shadow map depth with respect to the surface normal. diff --git a/Source/Engine/Level/Actors/PointLight.cpp b/Source/Engine/Level/Actors/PointLight.cpp index b5801166e..c30d47c08 100644 --- a/Source/Engine/Level/Actors/PointLight.cpp +++ b/Source/Engine/Level/Actors/PointLight.cpp @@ -15,8 +15,9 @@ PointLight::PointLight(const SpawnParams& params) { CastVolumetricShadow = false; ShadowsDistance = 2000.0f; - ShadowsFadeDistance = 100.0f; - ShadowsDepthBias = 0.5f; + ShadowsFadeDistance = 500.0f; + ShadowsDepthBias = 0.05f; + _direction = Float3::Forward; _sphere = BoundingSphere(Vector3::Zero, _radius); BoundingBox::FromSphere(_sphere, _box); diff --git a/Source/Engine/Level/Actors/SpotLight.cpp b/Source/Engine/Level/Actors/SpotLight.cpp index 38502cf1b..f733753ae 100644 --- a/Source/Engine/Level/Actors/SpotLight.cpp +++ b/Source/Engine/Level/Actors/SpotLight.cpp @@ -19,8 +19,8 @@ SpotLight::SpotLight(const SpawnParams& params) { CastVolumetricShadow = false; ShadowsDistance = 2000.0f; - ShadowsFadeDistance = 100.0f; - ShadowsDepthBias = 0.5f; + ShadowsFadeDistance = 500.0f; + ShadowsDepthBias = 0.05f; _direction = Vector3::Forward; _cosOuterCone = Math::Cos(_outerConeAngle * DegreesToRadians); diff --git a/Source/Engine/Renderer/ShadowsPass.cpp b/Source/Engine/Renderer/ShadowsPass.cpp index 1e2436604..bdb151194 100644 --- a/Source/Engine/Renderer/ShadowsPass.cpp +++ b/Source/Engine/Renderer/ShadowsPass.cpp @@ -635,9 +635,80 @@ void ShadowsPass::SetupLight(ShadowsCustomBuffer& shadows, RenderContext& render atlasLight.Bounds.Center = light.Position + renderContext.View.Origin; // Keep bounds in world-space to properly handle DirtyStaticBounds atlasLight.Bounds.Radius = 0.0f; - // Adjust bias to account for lower shadow quality - if (shadows.MaxShadowsQuality == 0) - atlasLight.Bias *= 1.5f; + // Adjust bias to account for lower shadow quality (mix between different shadow map resolution and filter size) to automatically hide artifacts + switch ((Quality)shadows.MaxShadowsQuality) + { + case Quality::Low: + switch (Graphics::ShadowMapsQuality) + { + case Quality::Low: + atlasLight.Bias += 0.003f; + break; + case Quality::Medium: + atlasLight.Bias += 0.001f; + break; + } + break; + case Quality::Medium: + switch (Graphics::ShadowMapsQuality) + { + case Quality::Low: + atlasLight.Bias += 0.008f; + break; + case Quality::Medium: + atlasLight.Bias += 0.003f; + break; + case Quality::High: + atlasLight.Bias += 0.001f; + break; + } + break; + case Quality::High: + switch (Graphics::ShadowMapsQuality) + { + case Quality::Low: + atlasLight.Bias += 0.012f; + break; + case Quality::Medium: + atlasLight.Bias += 0.006f; + break; + case Quality::High: + atlasLight.Bias += 0.002f; + break; + } + break; + } + if (!light.IsDirectionalLight) + { + switch ((Quality)shadows.MaxShadowsQuality) + { + case Quality::Medium: + switch (Graphics::ShadowMapsQuality) + { + case Quality::Low: + atlasLight.NormalOffsetScale += 25; + break; + case Quality::Medium: + atlasLight.NormalOffsetScale += 10; + break; + } + break; + case Quality::High: + switch (Graphics::ShadowMapsQuality) + { + case Quality::Low: + atlasLight.NormalOffsetScale += 20; + break; + case Quality::Medium: + atlasLight.NormalOffsetScale +=15; + break; + case Quality::High: + atlasLight.NormalOffsetScale += 5; + break; + } + break; + } + } } bool ShadowsPass::SetupLight(ShadowsCustomBuffer& shadows, RenderContext& renderContext, RenderContextBatch& renderContextBatch, RenderLocalLightData& light, ShadowAtlasLight& atlasLight) diff --git a/Source/Shaders/ShadowsSampling.hlsl b/Source/Shaders/ShadowsSampling.hlsl index b401844a3..029085429 100644 --- a/Source/Shaders/ShadowsSampling.hlsl +++ b/Source/Shaders/ShadowsSampling.hlsl @@ -334,6 +334,9 @@ float SampleShadowMapPCSS(Texture2D shadowMap, float2 shadowMapUV, float // Calculate penumbra size float penumbra = max(sceneDepth - avgBlockerDistance, 0.0); +#if defined(VULKAN) + sceneDepth *= lerp(1, 0.985f, saturate(penumbra * 4.0f)); // Fix shadow bias issues on Vulkan +#endif float filterRadius = penumbra * sourceAngle; filterRadius = max(filterRadius, minRadius); // Don't use too small filter near blockers to avoid jagged edges