Optimize SSAO rendering with depth bounds and half-res depth buffer

This commit is contained in:
Wojtek Figat
2026-01-20 00:22:27 +01:00
parent 877d57681d
commit 192d3d1a8e
8 changed files with 60 additions and 26 deletions

View File

@@ -22,6 +22,7 @@ void AmbientOcclusionSettings::BlendWith(AmbientOcclusionSettings& other, float
BLEND_FLOAT(Radius);
BLEND_FLOAT(FadeOutDistance);
BLEND_FLOAT(FadeDistance);
BLEND_ENUM(DepthResolution);
}
void GlobalIlluminationSettings::BlendWith(GlobalIlluminationSettings& other, float weight)

View File

@@ -217,10 +217,15 @@ API_ENUM(Attributes="Flags") enum class AmbientOcclusionSettingsOverride : int32
/// </summary>
FadeDistance = 1 << 5,
/// <summary>
/// Overrides <see cref="AmbientOcclusionSettings.DepthResolution"/> property.
/// </summary>
DepthResolution = 1 << 6,
/// <summary>
/// All properties.
/// </summary>
All = Enabled | Intensity | Power | Radius | FadeOutDistance | FadeDistance,
All = Enabled | Intensity | Power | Radius | FadeOutDistance | FadeDistance | DepthResolution,
};
/// <summary>
@@ -274,6 +279,12 @@ API_STRUCT() struct FLAXENGINE_API AmbientOcclusionSettings : ISerializable
API_FIELD(Attributes="Limit(0.0f), EditorOrder(5), PostProcessSetting((int)AmbientOcclusionSettingsOverride.FadeDistance)")
float FadeDistance = 500.0f;
/// <summary>
/// The depth buffer downscale option to optimize rendering performance. Full gives better quality, but half improves performance.
/// </summary>
API_FIELD(Attributes="EditorOrder(6), PostProcessSetting((int)AmbientOcclusionSettingsOverride.DepthResolution)")
ResolutionMode DepthResolution = ResolutionMode::Half;
public:
/// <summary>
/// Blends the settings using given weight.

View File

@@ -83,16 +83,17 @@ GPUTexture* RenderBuffers::RequestHalfResDepth(GPUContext* context)
if (LastFrameHalfResDepth == currentFrame)
return HalfResDepth;
const int32 halfDepthWidth = _width / 2;
const int32 halfDepthHeight = _height / 2;
const int32 halfDepthWidth = (_width + 1) / 2;
const int32 halfDepthHeight = (_height + 1) / 2;
const PixelFormat halfDepthFormat = GPU_DEPTH_BUFFER_PIXEL_FORMAT;
auto tempDesc = GPUTextureDescription::New2D(halfDepthWidth, halfDepthHeight, halfDepthFormat);
if (EnumHasAnyFlags(DepthBuffer->Flags(), GPUTextureFlags::ReadOnlyDepthView))
tempDesc.Flags = GPUTextureFlags::ShaderResource | GPUTextureFlags::DepthStencil | GPUTextureFlags::ReadOnlyDepthView;
LastFrameHalfResDepth = currentFrame;
if (HalfResDepth == nullptr)
{
// Missing buffer
auto tempDesc = GPUTextureDescription::New2D(halfDepthWidth, halfDepthHeight, halfDepthFormat);
tempDesc.Flags = GPUTextureFlags::ShaderResource | GPUTextureFlags::DepthStencil;
HalfResDepth = RenderTargetPool::Get(tempDesc);
RENDER_TARGET_POOL_SET_NAME(HalfResDepth, "HalfResDepth");
}
@@ -100,8 +101,6 @@ GPUTexture* RenderBuffers::RequestHalfResDepth(GPUContext* context)
{
// Wrong size buffer
RenderTargetPool::Release(HalfResDepth);
auto tempDesc = GPUTextureDescription::New2D(halfDepthWidth, halfDepthHeight, halfDepthFormat);
tempDesc.Flags = GPUTextureFlags::ShaderResource | GPUTextureFlags::DepthStencil;
HalfResDepth = RenderTargetPool::Get(tempDesc);
RENDER_TARGET_POOL_SET_NAME(HalfResDepth, "HalfResDepth");
}

View File

@@ -695,6 +695,15 @@ Float2 RenderTools::GetDepthBounds(const RenderView& view, const OrientedBoundin
return GetDepthBounds(view, Span<Float3>(corners, 8));
}
float RenderTools::GetDepthBounds(const RenderView& view, const Float3& point)
{
const Float4 pointClip = Matrix::TransformPosition(view.ViewProjection(), Float4(point, 1.0));
float depth = pointClip.Z / pointClip.W;
if (depth >= 1.0f)
depth = 0.0f; // Point is behind the view
return Math::Clamp(depth, 0.0f, 1.0f);
}
Float3 RenderTools::GetColorQuantizationError(PixelFormat format)
{
Float3 mantissaBits;

View File

@@ -148,6 +148,7 @@ public:
static Float2 GetDepthBounds(const RenderView& view, const Span<Float3>& points);
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);
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).