diff --git a/Source/Engine/Graphics/RenderTools.cpp b/Source/Engine/Graphics/RenderTools.cpp index a0848315f..898b884c2 100644 --- a/Source/Engine/Graphics/RenderTools.cpp +++ b/Source/Engine/Graphics/RenderTools.cpp @@ -704,6 +704,12 @@ float RenderTools::GetDepthBounds(const RenderView& view, const Float3& point, b return Math::Clamp(depth, 0.0f, 1.0f); } +float RenderTools::GetDepthBounds(const RenderView& view, float viewDistance, bool near) +{ + Float3 point = view.Position + view.Direction * (viewDistance * 2.0f); + return GetDepthBounds(view, point, near); +} + Float3 RenderTools::GetColorQuantizationError(PixelFormat format) { Float3 mantissaBits; diff --git a/Source/Engine/Graphics/RenderTools.h b/Source/Engine/Graphics/RenderTools.h index 6d5f16088..301e3888f 100644 --- a/Source/Engine/Graphics/RenderTools.h +++ b/Source/Engine/Graphics/RenderTools.h @@ -155,6 +155,7 @@ public: static Float2 GetDepthBounds(const RenderView& view, const BoundingBox& bounds); static Float2 GetDepthBounds(const RenderView& view, const OrientedBoundingBox& bounds); static float GetDepthBounds(const RenderView& view, const Float3& point, bool near); + static float GetDepthBounds(const RenderView& view, float viewDistance, bool near); static constexpr float DepthBoundMaxBackground = 1.0f - 0.0000001f; // Skip background/sky pixels from shading // Calculates error for a given render target format to reduce floating-point precision artifacts via QuantizeColor (from Noise.hlsl). diff --git a/Source/Engine/Renderer/AmbientOcclusionPass.cpp b/Source/Engine/Renderer/AmbientOcclusionPass.cpp index 1913784ee..a325f5f96 100644 --- a/Source/Engine/Renderer/AmbientOcclusionPass.cpp +++ b/Source/Engine/Renderer/AmbientOcclusionPass.cpp @@ -270,12 +270,12 @@ void AmbientOcclusionPass::Render(RenderContext& renderContext) // Cache data auto device = GPUDevice::Instance; auto context = device->GetMainContext(); - float m_sizeX = (float)renderContext.Buffers->GetWidth(); - float m_sizeY = (float)renderContext.Buffers->GetHeight(); - float m_halfSizeX = (m_sizeX + 1) / 2; - float m_halfSizeY = (m_sizeY + 1) / 2; + int32 m_sizeX = renderContext.Buffers->GetWidth(); + int32 m_sizeY = renderContext.Buffers->GetHeight(); + int32 m_halfSizeX = (m_sizeX + 1) / 2; + int32 m_halfSizeY = (m_sizeY + 1) / 2; GPUTexture* depthBuffer = aoSettings.DepthResolution == ResolutionMode::Full ? renderContext.Buffers->DepthBuffer : renderContext.Buffers->RequestHalfResDepth(context); - GPUTextureView* depthBufferApply = _depthBounds ? renderContext.Buffers->DepthBuffer ->ViewReadOnlyDepth() : nullptr; + GPUTextureView* depthBufferApply = _depthBounds ? renderContext.Buffers->DepthBuffer->ViewReadOnlyDepth() : nullptr; // Request temporary buffers GPUTexture* m_halfDepths[4]; @@ -287,20 +287,20 @@ void AmbientOcclusionPass::Render(RenderContext& renderContext) for (int i = 0; i < 4; i++) { #if SSAO_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET < 99 - tempDesc = GPUTextureDescription::New2D((int32)m_halfSizeX, (int32)m_halfSizeY, 0, SSAO_DEPTH_FORMAT, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::PerMipViews); + tempDesc = GPUTextureDescription::New2D(m_halfSizeX, m_halfSizeY, 0, SSAO_DEPTH_FORMAT, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::PerMipViews); #else - tempDesc = GPUTextureDescription::New2D((int32)m_halfSizeX, (int32)m_halfSizeY, SSAO_DEPTH_FORMAT, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget); + tempDesc = GPUTextureDescription::New2D(m_halfSizeX, m_halfSizeY, SSAO_DEPTH_FORMAT, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget); #endif m_halfDepths[i] = RenderTargetPool::Get(tempDesc); RENDER_TARGET_POOL_SET_NAME(m_halfDepths[i], "SSAO.HalfDepth"); } - tempDesc = GPUTextureDescription::New2D((int32)m_halfSizeX, (int32)m_halfSizeY, SSAO_AO_RESULT_FORMAT); + tempDesc = GPUTextureDescription::New2D(m_halfSizeX, m_halfSizeY, SSAO_AO_RESULT_FORMAT); m_pingPongHalfResultA = RenderTargetPool::Get(tempDesc); RENDER_TARGET_POOL_SET_NAME(m_pingPongHalfResultA, "SSAO.ResultsHalfA"); - tempDesc = GPUTextureDescription::New2D((int32)m_halfSizeX, (int32)m_halfSizeY, SSAO_AO_RESULT_FORMAT); + tempDesc = GPUTextureDescription::New2D(m_halfSizeX, m_halfSizeY, SSAO_AO_RESULT_FORMAT); m_pingPongHalfResultB = RenderTargetPool::Get(tempDesc); RENDER_TARGET_POOL_SET_NAME(m_pingPongHalfResultA, "SSAO.ResultsHalfB"); - tempDesc = GPUTextureDescription::New2D((int32)m_halfSizeX, (int32)m_halfSizeY, SSAO_AO_RESULT_FORMAT, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget, 4); + tempDesc = GPUTextureDescription::New2D(m_halfSizeX, m_halfSizeY, SSAO_AO_RESULT_FORMAT, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget, 4); m_finalResults = RenderTargetPool::Get(tempDesc); RENDER_TARGET_POOL_SET_NAME(m_finalResults, "SSAO.Results"); } @@ -318,11 +318,12 @@ void AmbientOcclusionPass::Render(RenderContext& renderContext) GBufferPass::SetInputs(view, _constantsBufferData.GBuffer); Matrix::Transpose(view.View, _constantsBufferData.ViewMatrix); - _constantsBufferData.ViewportPixelSize = Float2(1.0f / m_sizeX, 1.0f / m_sizeY); - _constantsBufferData.HalfViewportPixelSize = Float2(1.0f / m_halfSizeX, 1.0f / m_halfSizeY); + _constantsBufferData.ViewportPixelSize = Float2(1.0f / (float)m_sizeX, 1.0f / (float)m_sizeY); + _constantsBufferData.HalfViewportPixelSize = Float2(1.0f / (float)m_halfSizeX, 1.0f / (float)m_halfSizeY); _constantsBufferData.Viewport2xPixelSize = Float2(_constantsBufferData.ViewportPixelSize.X * 2.0f, _constantsBufferData.ViewportPixelSize.Y * 2.0f); _constantsBufferData.Viewport2xPixelSize_x_025 = Float2(_constantsBufferData.Viewport2xPixelSize.X * 0.25f, _constantsBufferData.Viewport2xPixelSize.Y * 0.25f); + _constantsBufferData.InputDepthScale = aoSettings.DepthResolution == ResolutionMode::Full ? 2 : 1; const float tanHalfFOVY = 1.0f / proj.Values[1][1]; @@ -375,7 +376,7 @@ void AmbientOcclusionPass::Render(RenderContext& renderContext) // Bind scene depth buffer and set proper viewport context->BindSR(SSAO_TEXTURE_SLOT0, depthBuffer); - context->SetViewportAndScissors(m_halfSizeX, m_halfSizeY); + context->SetViewportAndScissors((float)m_halfSizeX, (float)m_halfSizeY); // Prepare depth in half resolution { @@ -437,7 +438,7 @@ void AmbientOcclusionPass::Render(RenderContext& renderContext) // Generate SSAO (interleaved in checkerboard pattern) { - context->SetViewportAndScissors(m_halfSizeX, m_halfSizeY); + context->SetViewportAndScissors((float)m_halfSizeX, (float)m_halfSizeY); for (int32 pass = 0; pass < 4; pass++) { if (settings.SkipHalfPixels && ((pass == 1) || (pass == 2))) @@ -526,10 +527,9 @@ void AmbientOcclusionPass::Render(RenderContext& renderContext) } // Apply - Float3 depthBoundPoint = renderContext.View.Position + renderContext.View.Direction * (aoSettings.FadeOutDistance * 2.0f); - context->SetDepthBounds(0.0f, RenderTools::GetDepthBounds(renderContext.View, depthBoundPoint, false)); + context->SetDepthBounds(0.0f, RenderTools::GetDepthBounds(renderContext.View, aoSettings.FadeOutDistance, false)); context->BindSR(SSAO_TEXTURE_SLOT0, m_finalResults->ViewArray()); - context->SetViewportAndScissors(m_sizeX, m_sizeY); + context->SetViewportAndScissors((float)m_sizeX, (float)m_sizeY); context->SetState(settings.SkipHalfPixels ? _psApplyHalf : _psApply); context->SetRenderTarget(depthBufferApply, renderContext.Buffers->GBuffer0->View()); context->DrawFullscreenTriangle(); diff --git a/Source/Engine/Renderer/AmbientOcclusionPass.h b/Source/Engine/Renderer/AmbientOcclusionPass.h index 8728ff6df..16e3db3d5 100644 --- a/Source/Engine/Renderer/AmbientOcclusionPass.h +++ b/Source/Engine/Renderer/AmbientOcclusionPass.h @@ -31,6 +31,9 @@ private: int32 PassIndex; float EffectMaxDistance; + Float3 Padding0; + uint32 InputDepthScale; + Float2 Viewport2xPixelSize; Float2 Viewport2xPixelSize_x_025; diff --git a/Source/Engine/Renderer/ReflectionsPass.cpp b/Source/Engine/Renderer/ReflectionsPass.cpp index c7566470b..43ce6cd4b 100644 --- a/Source/Engine/Renderer/ReflectionsPass.cpp +++ b/Source/Engine/Renderer/ReflectionsPass.cpp @@ -362,15 +362,6 @@ void ReflectionsPass::Render(RenderContext& renderContext, GPUTextureView* light { ScreenSpaceReflectionsPass::Instance()->Render(renderContext, *reflectionsBuffer, lightBuffer); context->SetViewportAndScissors(renderContext.Task->GetViewport()); - - /* - // DEBUG_CODE - context->RestoreViewport(); - context->SetRenderTarget(output); - context->Draw(reflectionsRT); - return; - // DEBUG_CODE - */ } if (renderContext.View.Mode == ViewMode::Reflections) diff --git a/Source/Engine/Renderer/ScreenSpaceReflectionsPass.cpp b/Source/Engine/Renderer/ScreenSpaceReflectionsPass.cpp index 40fd4fc90..6338cfb67 100644 --- a/Source/Engine/Renderer/ScreenSpaceReflectionsPass.cpp +++ b/Source/Engine/Renderer/ScreenSpaceReflectionsPass.cpp @@ -166,14 +166,14 @@ void ScreenSpaceReflectionsPass::Render(RenderContext& renderContext, GPUTexture const int32 traceHeight = RenderTools::GetResolution(height, settings.RayTracePassResolution); const int32 resolveWidth = RenderTools::GetResolution(width, settings.ResolvePassResolution); const int32 resolveHeight = RenderTools::GetResolution(height, settings.ResolvePassResolution); - const int32 colorBufferWidth = width / 2; - const int32 colorBufferHeight = height / 2; - const int32 temporalWidth = width; - const int32 temporalHeight = height; + const int32 colorBufferWidth = RenderTools::GetResolution(width, ResolutionMode::Half); + const int32 colorBufferHeight = RenderTools::GetResolution(height, ResolutionMode::Half); + const int32 temporalWidth = resolveWidth; + const int32 temporalHeight = resolveHeight; const auto colorBufferMips = MipLevelsCount(colorBufferWidth, colorBufferHeight); // Prepare buffers - auto tempDesc = GPUTextureDescription::New2D(width / 2, height / 2, 0, PixelFormat::R11G11B10_Float, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::PerMipViews); + auto tempDesc = GPUTextureDescription::New2D(colorBufferWidth, colorBufferHeight, 0, PixelFormat::R11G11B10_Float, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::PerMipViews); auto colorBuffer0 = RenderTargetPool::Get(tempDesc); RENDER_TARGET_POOL_SET_NAME(colorBuffer0, "SSR.ColorBuffer0"); // TODO: maybe allocate colorBuffer1 smaller because mip0 is not used (the same as PostProcessingPass for Bloom), keep in sync to use the same buffer in frame @@ -305,9 +305,8 @@ void ScreenSpaceReflectionsPass::Render(RenderContext& renderContext, GPUTexture // and improves resolve pass performance (faster color texture lookups, less cache misses) // Also for high surface roughness values it adds more blur to the reflection tail which looks more realistic. - const auto filterMode = MultiScaler::FilterMode::GaussianBlur9; - // Downscale with gaussian blur + auto filterMode = PLATFORM_ANDROID || PLATFORM_IOS || PLATFORM_SWITCH ? MultiScaler::FilterMode::GaussianBlur5 : MultiScaler::FilterMode::GaussianBlur9; for (int32 mipLevel = 1; mipLevel < colorBufferMips; mipLevel++) { const int32 mipWidth = Math::Max(colorBufferWidth >> mipLevel, 1); diff --git a/Source/Shaders/SSAO.shader b/Source/Shaders/SSAO.shader index 5116b3cb9..91ddf50cb 100644 --- a/Source/Shaders/SSAO.shader +++ b/Source/Shaders/SSAO.shader @@ -81,6 +81,9 @@ int2 PerPassFullResCoordOffset; int PassIndex; float EffectMaxDistance; +float3 Padding0; +uint InputDepthScale; + float2 Viewport2xPixelSize; float2 Viewport2xPixelSize_x_025; // Viewport2xPixelSize * 0.25 (for fusing add+mul into mad) @@ -213,7 +216,7 @@ void PS_PrepareDepths(in float4 inPos : SV_POSITION, out float out0 : SV_Target0 float b = depths.z; float a = depths.w; #else - int3 baseCoord = int3(int2(inPos.xy) * 2, 0); + int3 baseCoord = int3(int2(inPos.xy) * InputDepthScale, 0); float c = g_DepthSource.Load(baseCoord, int2(0, 1)).x; float d = g_DepthSource.Load(baseCoord, int2(1, 1)).x; float b = g_DepthSource.Load(baseCoord, int2(1, 0)).x; @@ -230,7 +233,7 @@ void PS_PrepareDepths(in float4 inPos : SV_POSITION, out float out0 : SV_Target0 META_PS(true, FEATURE_LEVEL_ES2) void PS_PrepareDepthsHalf(in float4 inPos : SV_POSITION, out float out0 : SV_Target0, out float out1 : SV_Target1) { - int3 baseCoord = int3(int2(inPos.xy) * 2, 0); + int3 baseCoord = int3(int2(inPos.xy) * InputDepthScale, 0); float a = g_DepthSource.Load(baseCoord, int2(0, 0)).x; float d = g_DepthSource.Load(baseCoord, int2(1, 1)).x; diff --git a/Source/Shaders/SSR.hlsl b/Source/Shaders/SSR.hlsl index 1ea1593ce..537a7099d 100644 --- a/Source/Shaders/SSR.hlsl +++ b/Source/Shaders/SSR.hlsl @@ -58,9 +58,11 @@ float3 ScreenSpaceReflectionDirection(float2 uv, GBufferSample gBuffer, float3 v // Returns: xy: hitUV, z: hitMask, where hitUV is the result UV of hit pixel, hitMask is the normalized sample weight (0 if no hit). float3 TraceScreenSpaceReflection(float2 uv, GBufferSample gBuffer, Texture2D depthBuffer, float3 viewPos, float4x4 viewMatrix, float4x4 viewProjectionMatrix, float stepSize, float maxSamples = 20, bool temporal = false, float temporalTime = 0.0f, float worldAntiSelfOcclusionBias = 0.1f, float brdfBias = 0.82f, float drawDistance = 5000.0f, float roughnessThreshold = 0.4f, float edgeFade = 0.1f) { +#ifndef SSR_SKIP_INVALID_CHECK // Reject invalid pixels if (gBuffer.ShadingModel == SHADING_MODEL_UNLIT || gBuffer.Roughness > roughnessThreshold || gBuffer.ViewPos.z > drawDistance) return 0; +#endif // Calculate view space normal vector float3 normalVS = mul(gBuffer.Normal, (float3x3)viewMatrix); diff --git a/Source/Shaders/SSR.shader b/Source/Shaders/SSR.shader index 4e88d6299..b185c5969 100644 --- a/Source/Shaders/SSR.shader +++ b/Source/Shaders/SSR.shader @@ -1,5 +1,7 @@ // Copyright (c) Wojciech Figat. All rights reserved. +#define SSR_SKIP_INVALID_CHECK 1 + #include "./Flax/Common.hlsl" #include "./Flax/LightingCommon.hlsl" #include "./Flax/ReflectionsCommon.hlsl" @@ -13,7 +15,7 @@ #define SSR_REDUCE_HIGHLIGHTS 1 // Enable/disable blurring SSR during sampling results and mixing with reflections buffer -#define SSR_MIX_BLUR 1 +#define SSR_MIX_BLUR (!defined(PLATFORM_ANDROID) && !defined(PLATFORM_IOS) && !defined(PLATFORM_SWITCH)) META_CB_BEGIN(0, Data) GBufferData GBuffer; @@ -273,13 +275,11 @@ float4 PS_MixPass(Quad_VS2PS input) : SV_Target0 float4 ssr = Texture0.SampleLevel(SamplerLinearClamp, input.TexCoord, 0); #if SSR_MIX_BLUR - ssr += Texture0.SampleLevel(SamplerLinearClamp, input.TexCoord + float2(0, SSRtexelSize.y), 0); ssr += Texture0.SampleLevel(SamplerLinearClamp, input.TexCoord - float2(0, SSRtexelSize.y), 0); ssr += Texture0.SampleLevel(SamplerLinearClamp, input.TexCoord + float2(SSRtexelSize.x, 0), 0); ssr += Texture0.SampleLevel(SamplerLinearClamp, input.TexCoord - float2(SSRtexelSize.x, 0), 0); ssr *= (1.0f / 5.0f); - #endif ssr.a = saturate(ssr.a);