diff --git a/Source/Engine/Graphics/GPUContext.h b/Source/Engine/Graphics/GPUContext.h
index 110770314..9a55957ce 100644
--- a/Source/Engine/Graphics/GPUContext.h
+++ b/Source/Engine/Graphics/GPUContext.h
@@ -15,9 +15,13 @@
#endif
#if FLAX_REVERSE_Z
-#define GPU_DEPTH_CLEAR_VALUE 0.0f
+#define GPU_DEPTH_MIN_VALUE 1.0f
+#define GPU_DEPTH_MAX_VALUE 0.0f
+#define GPU_DEPTH_BOUNDS_SWAP(min, max) max, min
#else
-#define GPU_DEPTH_CLEAR_VALUE 1.0f
+#define GPU_DEPTH_MIN_VALUE 0.0f
+#define GPU_DEPTH_MAX_VALUE 1.0f
+#define GPU_DEPTH_BOUNDS_SWAP(min, max) min, max
#endif
class GPUConstantBuffer;
@@ -214,7 +218,7 @@ public:
/// The depth buffer to clear.
/// The clear depth value.
/// The clear stencil value.
- API_FUNCTION() virtual void ClearDepth(GPUTextureView* depthBuffer, float depthValue = GPU_DEPTH_CLEAR_VALUE, uint8 stencilValue = 0) = 0;
+ API_FUNCTION() virtual void ClearDepth(GPUTextureView* depthBuffer, float depthValue = GPU_DEPTH_MAX_VALUE, uint8 stencilValue = 0) = 0;
///
/// Clears an unordered access buffer with a float value.
@@ -634,9 +638,10 @@ public:
///
/// Sets the minimum and maximum depth values for depth bounds test.
///
+ /// Both values must be between 0.0 and 1.0, MinDepth must be less than or equal to MaxDepth.
/// The minimum value for depth bound test.
/// The maximum value for depth bound test.
- API_FUNCTION() virtual void SetDepthBounds(float minDepth, float maxDepth) = 0;
+ API_FUNCTION() virtual void SetDepthBounds(float minDepth = 0.0f, float maxDepth = 1.0f) = 0;
public:
///
diff --git a/Source/Engine/Graphics/RenderTools.cpp b/Source/Engine/Graphics/RenderTools.cpp
index 5a7ca9079..d57c6b743 100644
--- a/Source/Engine/Graphics/RenderTools.cpp
+++ b/Source/Engine/Graphics/RenderTools.cpp
@@ -684,6 +684,20 @@ float RenderTools::TemporalHalton(int32 index, int32 base)
Float2 RenderTools::GetDepthBounds(const RenderView& view, const Float3& nearPoint, const Float3& farPoint)
{
+#if FLAX_REVERSE_Z
+ Float3 viewNearPoint = Float3::Transform(nearPoint, view.View);
+ Float3 viewFarPoint = Float3::Transform(farPoint, view.View);
+
+ viewNearPoint.Z = Math::Max(viewNearPoint.Z, view.Near);
+ viewFarPoint.Z = Math::Min(viewFarPoint.Z, view.Far);
+
+ Float4 clipNearPoint = Matrix::TransformPosition(view.Projection, Float4(0, 0, viewNearPoint.Z, 1));
+ Float4 clipFarPoint = Matrix::TransformPosition(view.Projection, Float4(0, 0, viewFarPoint.Z, 1));
+ clipNearPoint /= clipNearPoint.W;
+ clipFarPoint /= clipFarPoint.W;
+
+ return Float2(clipNearPoint.Z, clipFarPoint.Z);
+#else
// Point closest the view
const Float4 nearPointClip = Matrix::TransformPosition(view.ViewProjection(), Float4(nearPoint, 1.0));
float nearDepth = nearPointClip.Z / nearPointClip.W;
@@ -700,8 +714,8 @@ Float2 RenderTools::GetDepthBounds(const RenderView& view, const Float3& nearPoi
nearDepth = Math::Clamp(nearDepth, 0.0f, 1.0f);
farDepth = Math::Clamp(farDepth, nearDepth, 1.0f);
- // TODO: swap depths when using reversed depth buffer
return Float2(nearDepth, farDepth);
+#endif
}
Float2 RenderTools::GetDepthBounds(const RenderView& view, const BoundingSphere& bounds)
@@ -713,6 +727,24 @@ Float2 RenderTools::GetDepthBounds(const RenderView& view, const BoundingSphere&
Float2 RenderTools::GetDepthBounds(const RenderView& view, const Span& points)
{
+#if FLAX_REVERSE_Z
+ // Find min and max view depth range for list of points
+ float nearDepth = view.Far, farDepth = view.Near;
+ for (int32 i = 0; i < points.Length(); i++)
+ {
+ const Float3 viewPoint = Float3::Transform(points[i], view.View);
+ nearDepth = Math::Min(nearDepth, viewPoint.Z);
+ farDepth = Math::Max(farDepth, viewPoint.Z);
+ }
+
+ // Project end points to clip space
+ Float4 clipNearPoint = Matrix::TransformPosition(view.Projection, Float4(0, 0, nearDepth, 1));
+ Float4 clipFarPoint = Matrix::TransformPosition(view.Projection, Float4(0, 0, farDepth, 1));
+ clipNearPoint /= clipNearPoint.W;
+ clipFarPoint /= clipFarPoint.W;
+
+ return Float2(clipNearPoint.Z, clipFarPoint.Z);
+#else
// Find min and max depth range for list of points
float nearDepth = 1.0f, farDepth = 0.0f;
for (int32 i = 0; i < points.Length(); i++)
@@ -729,8 +761,8 @@ Float2 RenderTools::GetDepthBounds(const RenderView& view, const Span& p
nearDepth = Math::Clamp(nearDepth, 0.0f, 1.0f);
farDepth = Math::Clamp(farDepth, nearDepth, 1.0f);
- // TODO: swap depths when using reversed depth buffer
return Float2(nearDepth, farDepth);
+#endif
}
Float2 RenderTools::GetDepthBounds(const RenderView& view, const BoundingBox& bounds)
@@ -749,11 +781,21 @@ Float2 RenderTools::GetDepthBounds(const RenderView& view, const OrientedBoundin
float RenderTools::GetDepthBounds(const RenderView& view, const Float3& point, bool near)
{
+#if FLAX_REVERSE_Z
+ Float3 viewPoint = Float3::Transform(point, view.View);
+ viewPoint.Z = Math::Clamp(viewPoint.Z, view.Near, view.Far);
+
+ Float4 clipPoint = Matrix::TransformPosition(view.Projection, Float4(0, 0, viewPoint.Z, 1));
+ clipPoint /= clipPoint.W;
+
+ return clipPoint.Z;
+#else
const Float4 pointClip = Matrix::TransformPosition(view.ViewProjection(), Float4(point, 1.0));
float depth = pointClip.Z / pointClip.W;
if (depth >= 1.0f)
depth = near ? 0.0f : 1.0f; // Point is behind the view
return Math::Clamp(depth, 0.0f, 1.0f);
+#endif
}
float RenderTools::GetDepthBounds(const RenderView& view, float viewDistance, bool near)
diff --git a/Source/Engine/Graphics/RenderTools.h b/Source/Engine/Graphics/RenderTools.h
index 8c565eed5..87880d084 100644
--- a/Source/Engine/Graphics/RenderTools.h
+++ b/Source/Engine/Graphics/RenderTools.h
@@ -173,7 +173,12 @@ public:
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
+ // Skip background/sky pixels from shading
+#if FLAX_REVERSE_Z
+ static constexpr float DepthBoundMaxBackground = 0.0000001f;
+#else
+ static constexpr float DepthBoundMaxBackground = 1.0f - 0.0000001f;
+#endif
// Calculates error for a given render target format to reduce floating-point precision artifacts via QuantizeColor (from Noise.hlsl).
static Float3 GetColorQuantizationError(PixelFormat format);
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp
index 277272181..0aded637a 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp
@@ -796,9 +796,8 @@ void GPUContextVulkan::OnDrawCall()
if (_psDirtyFlag && pipelineState && (_rtDepth || _rtCount))
{
_psDirtyFlag = false;
- const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer()->GetHandle();
const auto pipeline = pipelineState->GetState(_renderPass, _vertexLayout);
- vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
+ vkCmdBindPipeline(cmdBuffer->GetHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
RENDER_STAT_PS_STATE_CHANGE();
if (_depthBoundsEnable && (!_currentState || !_currentState->DepthBoundsEnable))
{
diff --git a/Source/Engine/Renderer/AmbientOcclusionPass.cpp b/Source/Engine/Renderer/AmbientOcclusionPass.cpp
index 2766fe465..02f03094f 100644
--- a/Source/Engine/Renderer/AmbientOcclusionPass.cpp
+++ b/Source/Engine/Renderer/AmbientOcclusionPass.cpp
@@ -536,7 +536,7 @@ void AmbientOcclusionPass::Render(RenderContext& renderContext)
}
// Apply
- context->SetDepthBounds(0.0f, RenderTools::GetDepthBounds(renderContext.View, aoSettings.FadeOutDistance, false));
+ context->SetDepthBounds(GPU_DEPTH_BOUNDS_SWAP(GPU_DEPTH_MIN_VALUE, RenderTools::GetDepthBounds(renderContext.View, aoSettings.FadeOutDistance, false)));
context->BindSR(SSAO_TEXTURE_SLOT0, m_finalResults->ViewArray());
context->SetViewportAndScissors((float)m_sizeX, (float)m_sizeY);
context->SetState(settings.SkipHalfPixels ? _psApplyHalf : _psApply);
diff --git a/Source/Engine/Renderer/LightPass.cpp b/Source/Engine/Renderer/LightPass.cpp
index 1cad5fa31..bde260423 100644
--- a/Source/Engine/Renderer/LightPass.cpp
+++ b/Source/Engine/Renderer/LightPass.cpp
@@ -283,7 +283,7 @@ void LightPass::RenderLights(RenderContextBatch& renderContextBatch, GPUTextureV
if (_depthBounds)
{
Float2 minMaxDepth = RenderTools::GetDepthBounds(view, BoundingSphere(light.Position, light.Radius));
- context->SetDepthBounds(minMaxDepth.X, minMaxDepth.Y);
+ context->SetDepthBounds(GPU_DEPTH_BOUNDS_SWAP(minMaxDepth.X, minMaxDepth.Y));
}
context->UpdateCB(cb0, &perLight);
context->BindCB(0, cb0);
@@ -331,7 +331,7 @@ void LightPass::RenderLights(RenderContextBatch& renderContextBatch, GPUTextureV
if (_depthBounds)
{
Float2 minMaxDepth = RenderTools::GetDepthBounds(view, BoundingSphere(light.Position, light.Radius));
- context->SetDepthBounds(minMaxDepth.X, minMaxDepth.Y);
+ context->SetDepthBounds(GPU_DEPTH_BOUNDS_SWAP(minMaxDepth.X, minMaxDepth.Y));
}
context->UpdateCB(cb0, &perLight);
context->BindCB(0, cb0);
@@ -365,7 +365,7 @@ void LightPass::RenderLights(RenderContextBatch& renderContextBatch, GPUTextureV
// Calculate lighting
if (_depthBounds)
- context->SetDepthBounds(0.0f, RenderTools::DepthBoundMaxBackground);
+ context->SetDepthBounds(GPU_DEPTH_BOUNDS_SWAP(GPU_DEPTH_MIN_VALUE, RenderTools::DepthBoundMaxBackground));
context->UpdateCB(cb0, &perLight);
context->BindCB(0, cb0);
context->BindCB(1, cb1);
@@ -398,7 +398,7 @@ void LightPass::RenderLights(RenderContextBatch& renderContextBatch, GPUTextureV
if (_depthBounds)
{
Float2 minMaxDepth = RenderTools::GetDepthBounds(view, BoundingSphere(light.Position, light.Radius));
- context->SetDepthBounds(minMaxDepth.X, minMaxDepth.Y);
+ context->SetDepthBounds(GPU_DEPTH_BOUNDS_SWAP(minMaxDepth.X, minMaxDepth.Y));
}
context->UpdateCB(cb0, &perLight);
context->BindCB(0, cb0);
@@ -411,7 +411,7 @@ void LightPass::RenderLights(RenderContextBatch& renderContextBatch, GPUTextureV
// Restore state
if (_depthBounds)
- context->SetDepthBounds(0, 1);
+ context->SetDepthBounds();
context->ResetRenderTarget();
context->ResetSR();
context->ResetCB();
diff --git a/Source/Engine/Renderer/ReflectionsPass.cpp b/Source/Engine/Renderer/ReflectionsPass.cpp
index 9723b4c30..1dbd0cbc2 100644
--- a/Source/Engine/Renderer/ReflectionsPass.cpp
+++ b/Source/Engine/Renderer/ReflectionsPass.cpp
@@ -347,7 +347,7 @@ void ReflectionsPass::Render(RenderContext& renderContext, GPUTextureView* light
// Setup depth bounds (if device supports it)
if (_depthBounds)
- context->SetDepthBounds(minMaxDepth.X, minMaxDepth.Y);
+ context->SetDepthBounds(GPU_DEPTH_BOUNDS_SWAP(minMaxDepth.X, minMaxDepth.Y));
// Pack probe properties buffer
probe.SetShaderData(data.PData);
@@ -368,7 +368,7 @@ void ReflectionsPass::Render(RenderContext& renderContext, GPUTextureView* light
context->UnBindSR(4);
context->ResetRenderTarget();
if (_depthBounds)
- context->SetDepthBounds(0, 1);
+ context->SetDepthBounds();
}
// Screen Space Reflections pass
@@ -417,7 +417,7 @@ void ReflectionsPass::Render(RenderContext& renderContext, GPUTextureView* light
if (_depthBounds)
{
context->SetRenderTarget(depthBufferRTV, lightBuffer);
- context->SetDepthBounds(0, RenderTools::DepthBoundMaxBackground);
+ context->SetDepthBounds(GPU_DEPTH_BOUNDS_SWAP(GPU_DEPTH_MIN_VALUE, RenderTools::DepthBoundMaxBackground));
}
else
context->SetRenderTarget(lightBuffer);
@@ -430,7 +430,7 @@ void ReflectionsPass::Render(RenderContext& renderContext, GPUTextureView* light
context->SetState(_psCombinePass);
context->DrawFullscreenTriangle();
if (_depthBounds)
- context->SetDepthBounds(0, 1);
+ context->SetDepthBounds();
}
RenderTargetPool::Release(ssrBuffer);
diff --git a/Source/Engine/Renderer/ShadowsPass.cpp b/Source/Engine/Renderer/ShadowsPass.cpp
index b21a37e9d..ccdf2fff5 100644
--- a/Source/Engine/Renderer/ShadowsPass.cpp
+++ b/Source/Engine/Renderer/ShadowsPass.cpp
@@ -1147,11 +1147,7 @@ void ShadowsPass::SetupLight(ShadowsCustomBuffer& shadows, RenderContext& render
void ShadowsPass::ClearShadowMapTile(GPUContext* context, GPUConstantBuffer* quadShaderCB, QuadShaderData& quadShaderData) const
{
// Color.r is used by PS_DepthClear in Quad shader to clear depth
-#if FLAX_REVERSE_Z
- quadShaderData.Color = Float4::Zero;
-#else
- quadShaderData.Color = Float4::One;
-#endif
+ quadShaderData.Color = GPU_DEPTH_MAX_VALUE;
context->UpdateCB(quadShaderCB, &quadShaderData);
context->BindCB(0, quadShaderCB);
@@ -1753,8 +1749,8 @@ void ShadowsPass::RenderShadowMask(RenderContextBatch& renderContextBatch, Rende
if (light.IsPointLight || light.IsSpotLight)
minMaxDepth = RenderTools::GetDepthBounds(view, BoundingSphere(light.Position, ((RenderLocalLightData&)light).Radius));
else //if (light.IsDirectionalLight)
- minMaxDepth = Float2(0.0f, RenderTools::DepthBoundMaxBackground);
- context->SetDepthBounds(minMaxDepth.X, minMaxDepth.Y);
+ minMaxDepth = Float2(GPU_DEPTH_MIN_VALUE, RenderTools::DepthBoundMaxBackground);
+ context->SetDepthBounds(GPU_DEPTH_BOUNDS_SWAP(minMaxDepth.X, minMaxDepth.Y));
}
if (light.IsPointLight)
{