Fixes for SSAO and SSR
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -31,6 +31,9 @@ private:
|
||||
int32 PassIndex;
|
||||
float EffectMaxDistance;
|
||||
|
||||
Float3 Padding0;
|
||||
uint32 InputDepthScale;
|
||||
|
||||
Float2 Viewport2xPixelSize;
|
||||
Float2 Viewport2xPixelSize_x_025;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user