diff --git a/Source/Editor/Gizmo/SelectionOutline.cs b/Source/Editor/Gizmo/SelectionOutline.cs index 410650e4f..00f83ccac 100644 --- a/Source/Editor/Gizmo/SelectionOutline.cs +++ b/Source/Editor/Gizmo/SelectionOutline.cs @@ -147,7 +147,11 @@ namespace FlaxEditor.Gizmo _material.SetParameterValue("OutlineColor0", _color0); _material.SetParameterValue("OutlineColor1", _color1); _material.SetParameterValue("CustomDepth", customDepth); - _material.SetParameterValue("ViewInfo", new Float4(1.0f / projection.M11, 1.0f / projection.M22, far / (far - near), (-far * near) / (far - near) / far)); +#if FLAX_REVERSE_Z + _material.SetParameterValue("ViewInfo", new Float4(1.0f / projection.M11, 1.0f / projection.M22, -near / (far - near), (far * near) / (far - near) / far)); +#else + _material.SetParameterValue("ViewInfo", new Float4(1.0f / projection.M11, 1.0f / projection.M22, far / (far - near), -(far * near) / (far - near) / far)); +#endif Renderer.DrawPostFxMaterial(context, ref renderContext, _material, output, input.View()); // Cleanup diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs index fa5724780..e6a1c436d 100644 --- a/Source/Editor/Viewport/EditorViewport.cs +++ b/Source/Editor/Viewport/EditorViewport.cs @@ -1497,9 +1497,14 @@ namespace FlaxEditor.Viewport Matrix.Multiply(ref v, ref p, out var ivp); ivp.Invert(); - // Create near and far points - var nearPoint = new Vector3(mousePosition, _nearPlane); - var farPoint = new Vector3(mousePosition, _farPlane); + // Create near and far points, with device depth of 1 and 0 respectively +#if FLAX_REVERSE_Z + var nearPoint = new Vector3(mousePosition, 1.0f); + var farPoint = new Vector3(mousePosition, 0.0f); +#else + var nearPoint = new Vector3(mousePosition, 0.0f); + var farPoint = new Vector3(mousePosition, 1.0f); +#endif viewport.Unproject(ref nearPoint, ref ivp, out nearPoint); viewport.Unproject(ref farPoint, ref ivp, out farPoint); diff --git a/Source/Engine/Core/Math/BoundingFrustum.cpp b/Source/Engine/Core/Math/BoundingFrustum.cpp index e0697ce5e..091badd72 100644 --- a/Source/Engine/Core/Math/BoundingFrustum.cpp +++ b/Source/Engine/Core/Math/BoundingFrustum.cpp @@ -59,6 +59,11 @@ void BoundingFrustum::SetMatrix(const Matrix& matrix) _pFar.Normal.Z = matrix.M34 - matrix.M33; _pFar.D = matrix.M44 - matrix.M43; _pFar.Normalize(); + +#if FLAX_REVERSE_Z + // Swap far and near planes if reverse z + Swap(_pFar, _pNear); +#endif } Plane BoundingFrustum::GetPlane(int32 index) const diff --git a/Source/Engine/Core/Math/BoundingFrustum.cs b/Source/Engine/Core/Math/BoundingFrustum.cs index 4f1e27e1e..aa2f09d53 100644 --- a/Source/Engine/Core/Math/BoundingFrustum.cs +++ b/Source/Engine/Core/Math/BoundingFrustum.cs @@ -243,6 +243,11 @@ namespace FlaxEngine far.Normal.Z = matrix.M34 - matrix.M33; far.D = matrix.M44 - matrix.M43; far.Normalize(); + +#if FLAX_REVERSE_Z + // Swap far and near planes if reverse z + (near, far) = (far, near); +#endif } private static Vector3 Get3PlanesInterPoint(ref Plane p1, ref Plane p2, ref Plane p3) diff --git a/Source/Engine/Core/Math/Matrix.cpp b/Source/Engine/Core/Math/Matrix.cpp index f8ee50c42..9902e5bdd 100644 --- a/Source/Engine/Core/Math/Matrix.cpp +++ b/Source/Engine/Core/Math/Matrix.cpp @@ -522,10 +522,15 @@ void Matrix::OrthoOffCenter(float left, float right, float bottom, float top, fl result = Identity; result.M11 = 2.0f / (right - left); result.M22 = 2.0f / (top - bottom); - result.M33 = zRange; result.M41 = (left + right) / (left - right); result.M42 = (top + bottom) / (bottom - top); +#if FLAX_REVERSE_Z + result.M33 = -zRange; + result.M43 = zFar * zRange; +#else + result.M33 = zRange; result.M43 = -zNear * zRange; +#endif } void Matrix::PerspectiveFov(float fov, float aspect, float zNear, float zFar, Matrix& result) @@ -541,16 +546,21 @@ void Matrix::PerspectiveFov(float fov, float aspect, float zNear, float zFar, Ma void Matrix::PerspectiveOffCenter(float left, float right, float bottom, float top, float zNear, float zFar, Matrix& result) { - const float zRange = zFar / (zFar - zNear); + const float zRange = 1.0f / (zFar - zNear); result = Zero; result.M11 = 2.0f * zNear / (right - left); result.M22 = 2.0f * zNear / (top - bottom); result.M31 = (left + right) / (left - right); result.M32 = (top + bottom) / (bottom - top); - result.M33 = zRange; result.M34 = 1.0f; - result.M43 = -zNear * zRange; +#if FLAX_REVERSE_Z + result.M33 = -zNear * zRange; + result.M43 = zFar * zNear * zRange; +#else + result.M33 = zFar * zRange; + result.M43 = -zFar * zNear * zRange; +#endif } void Matrix::RotationX(float angle, Matrix& result) diff --git a/Source/Engine/Core/Math/Matrix.cs b/Source/Engine/Core/Math/Matrix.cs index 07ab2dea9..fab146a9e 100644 --- a/Source/Engine/Core/Math/Matrix.cs +++ b/Source/Engine/Core/Math/Matrix.cs @@ -2176,10 +2176,15 @@ namespace FlaxEngine result = Identity; result.M11 = 2.0f / (right - left); result.M22 = 2.0f / (top - bottom); - result.M33 = zRange; result.M41 = (left + right) / (left - right); result.M42 = (top + bottom) / (bottom - top); +#if FLAX_REVERSE_Z + result.M33 = -zRange; + result.M43 = zfar * zRange; +#else + result.M33 = zRange; result.M43 = -znear * zRange; +#endif } /// @@ -2238,14 +2243,19 @@ namespace FlaxEngine public static void PerspectiveFov(float fov, float aspect, float znear, float zfar, out Matrix result) { var yScale = (float)(1.0f / Math.Tan(fov * 0.5f)); - var q = zfar / (zfar - znear); + var zRange = 1.0f / (zfar - znear); result = new Matrix { M11 = yScale / aspect, M22 = yScale, - M33 = q, M34 = 1.0f, - M43 = -q * znear, +#if FLAX_REVERSE_Z + M33 = -znear * zRange, + M43 = znear * zfar * zRange, +#else + M33 = zfar * zRange, + M43 = -znear * zfar * zRange, +#endif }; } @@ -2275,16 +2285,21 @@ namespace FlaxEngine /// When the method completes, contains the created projection matrix. public static void PerspectiveOffCenter(float left, float right, float bottom, float top, float znear, float zfar, out Matrix result) { - float zRange = zfar / (zfar - znear); + float zRange = 1.0f / (zfar - znear); result = new Matrix { M11 = 2.0f * znear / (right - left), M22 = 2.0f * znear / (top - bottom), M31 = (left + right) / (left - right), M32 = (top + bottom) / (bottom - top), - M33 = zRange, M34 = 1.0f, - M43 = -znear * zRange, +#if FLAX_REVERSE_Z + M33 = -znear * zRange, + M43 = znear * zfar * zRange, +#else + M33 = zfar * zRange, + M43 = -znear * zfar * zRange, +#endif }; } diff --git a/Source/Engine/Core/Math/Viewport.cs b/Source/Engine/Core/Math/Viewport.cs index f2be10457..b4ff20dd9 100644 --- a/Source/Engine/Core/Math/Viewport.cs +++ b/Source/Engine/Core/Math/Viewport.cs @@ -296,15 +296,13 @@ namespace FlaxEngine /// /// Converts a screen space point into a corresponding point in world space. /// - /// The vector to project. + /// The vector to project, screen uv and device depth. /// The projection matrix. /// The view matrix. - /// The world matrix. /// The unprojected Vector. - public Vector3 Unproject(Vector3 source, Matrix projection, Matrix view, Matrix world) + public Vector3 Unproject(Vector3 source, Matrix projection, Matrix view) { - Matrix.Multiply(ref world, ref view, out Matrix matrix); - Matrix.Multiply(ref matrix, ref projection, out matrix); + Matrix.Multiply(ref view, ref projection, out Matrix matrix); Matrix.Invert(ref matrix, out matrix); Unproject(ref source, ref matrix, out Vector3 vector); @@ -314,8 +312,8 @@ namespace FlaxEngine /// /// Converts a screen space point into a corresponding point in world space. /// - /// The vector to project. - /// An inverted combined WorldViewProjection matrix. + /// The vector to project, screen uv and device depth. + /// An inverted combined ViewProjection matrix. /// The unprojected vector. public void Unproject(ref Vector3 source, ref Matrix matrix, out Vector3 vector) { diff --git a/Source/Engine/Graphics/GPUContext.h b/Source/Engine/Graphics/GPUContext.h index 3a103d3da..110770314 100644 --- a/Source/Engine/Graphics/GPUContext.h +++ b/Source/Engine/Graphics/GPUContext.h @@ -14,6 +14,12 @@ #undef MemoryBarrier #endif +#if FLAX_REVERSE_Z +#define GPU_DEPTH_CLEAR_VALUE 0.0f +#else +#define GPU_DEPTH_CLEAR_VALUE 1.0f +#endif + class GPUConstantBuffer; class GPUShaderProgramCS; class GPUBuffer; @@ -208,7 +214,7 @@ public: /// The depth buffer to clear. /// The clear depth value. /// The clear stencil value. - API_FUNCTION() virtual void ClearDepth(GPUTextureView* depthBuffer, float depthValue = 1.0f, uint8 stencilValue = 0) = 0; + API_FUNCTION() virtual void ClearDepth(GPUTextureView* depthBuffer, float depthValue = GPU_DEPTH_CLEAR_VALUE, uint8 stencilValue = 0) = 0; /// /// Clears an unordered access buffer with a float value. diff --git a/Source/Engine/Graphics/GPUDevice.cpp b/Source/Engine/Graphics/GPUDevice.cpp index c96dcc0a3..fb59ee22b 100644 --- a/Source/Engine/Graphics/GPUDevice.cpp +++ b/Source/Engine/Graphics/GPUDevice.cpp @@ -160,7 +160,11 @@ GPUPipelineState::Description GPUPipelineState::Description::Default = true, // DepthWriteEnable true, // DepthClipEnable false, // DepthBoundsEnable +#if FLAX_REVERSE_Z + ComparisonFunc::Greater, // DepthFunc +#else ComparisonFunc::Less, // DepthFunc +#endif false, // StencilEnable 0xff, // StencilReadMask 0xff, // StencilWriteMask @@ -185,7 +189,11 @@ GPUPipelineState::Description GPUPipelineState::Description::DefaultNoDepth = false, // DepthWriteEnable false, // DepthClipEnable false, // DepthBoundsEnable +#if FLAX_REVERSE_Z + ComparisonFunc::Greater, // DepthFunc +#else ComparisonFunc::Less, // DepthFunc +#endif false, // StencilEnable 0xff, // StencilReadMask 0xff, // StencilWriteMask @@ -210,7 +218,11 @@ GPUPipelineState::Description GPUPipelineState::Description::DefaultFullscreenTr false, // DepthWriteEnable false, // DepthClipEnable false, // DepthBoundsEnable +#if FLAX_REVERSE_Z + ComparisonFunc::Greater, // DepthFunc +#else ComparisonFunc::Less, // DepthFunc +#endif false, // StencilEnable 0xff, // StencilReadMask 0xff, // StencilWriteMask diff --git a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp index ea052aa84..9dca94b87 100644 --- a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp @@ -182,7 +182,11 @@ bool DeferredMaterialShader::Load() // Motion Vectors pass psDesc.DepthWriteEnable = false; psDesc.DepthEnable = true; +#if FLAX_REVERSE_Z + psDesc.DepthFunc = ComparisonFunc::GreaterEqual; +#else psDesc.DepthFunc = ComparisonFunc::LessEqual; +#endif psDesc.VS = _shader->GetVS("VS"); psDesc.PS = _shader->GetPS("PS_MotionVectors"); _cache.MotionVectors.Init(psDesc); @@ -200,7 +204,11 @@ bool DeferredMaterialShader::Load() psDesc.DepthClipEnable = false; psDesc.DepthWriteEnable = true; psDesc.DepthEnable = true; +#if FLAX_REVERSE_Z + psDesc.DepthFunc = ComparisonFunc::Greater; +#else psDesc.DepthFunc = ComparisonFunc::Less; +#endif psDesc.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::None; psDesc.HS = nullptr; psDesc.DS = nullptr; diff --git a/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp index 6260163f4..77e3072a9 100644 --- a/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp @@ -178,7 +178,11 @@ bool DeformableMaterialShader::Load() psDesc.DepthClipEnable = false; psDesc.DepthWriteEnable = true; psDesc.DepthEnable = true; +#if FLAX_REVERSE_Z + psDesc.DepthFunc = ComparisonFunc::Greater; +#else psDesc.DepthFunc = ComparisonFunc::Less; +#endif psDesc.HS = nullptr; psDesc.DS = nullptr; _cache.Depth.Init(psDesc); diff --git a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp index f5897fc46..a0c3e77a0 100644 --- a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp @@ -185,7 +185,11 @@ bool ForwardMaterialShader::Load() psDesc.DepthClipEnable = false; psDesc.DepthWriteEnable = true; psDesc.DepthEnable = true; +#if FLAX_REVERSE_Z + psDesc.DepthFunc = ComparisonFunc::Greater; +#else psDesc.DepthFunc = ComparisonFunc::Less; +#endif psDesc.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::None; psDesc.HS = nullptr; psDesc.DS = nullptr; diff --git a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp index bb0796234..7dd266596 100644 --- a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp @@ -189,7 +189,11 @@ bool TerrainMaterialShader::Load() psDesc.DepthClipEnable = false; psDesc.DepthWriteEnable = true; psDesc.DepthEnable = true; +#if FLAX_REVERSE_Z + psDesc.DepthFunc = ComparisonFunc::Greater; +#else psDesc.DepthFunc = ComparisonFunc::Less; +#endif psDesc.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::None; psDesc.HS = nullptr; psDesc.DS = nullptr; diff --git a/Source/Engine/Graphics/RenderView.cpp b/Source/Engine/Graphics/RenderView.cpp index 0472ce346..bdfe43882 100644 --- a/Source/Engine/Graphics/RenderView.cpp +++ b/Source/Engine/Graphics/RenderView.cpp @@ -65,7 +65,11 @@ void RenderView::Prepare(RenderContext& renderContext) void RenderView::PrepareCache(const RenderContext& renderContext, float width, float height, const Float2& temporalAAJitter, const RenderView* mainView) { // The same format used by the Flax common shaders and postFx materials - ViewInfo = Float4(1.0f / Projection.M11, 1.0f / Projection.M22, Far / (Far - Near), (-Far * Near) / (Far - Near) / Far); +#if FLAX_REVERSE_Z + ViewInfo = Float4(1.0f / Projection.M11, 1.0f / Projection.M22, -Near / (Far - Near), (Far * Near) / (Far - Near) / Far); +#else + ViewInfo = Float4(1.0f / Projection.M11, 1.0f / Projection.M22, Far / (Far - Near), -(Far * Near) / (Far - Near) / Far); +#endif ScreenSize = Float4(width, height, 1.0f / width, 1.0f / height); TemporalAAJitter.Z = TemporalAAJitter.X; diff --git a/Source/Engine/Level/Actors/Sky.cpp b/Source/Engine/Level/Actors/Sky.cpp index 7354f3bcf..5f5e34c29 100644 --- a/Source/Engine/Level/Actors/Sky.cpp +++ b/Source/Engine/Level/Actors/Sky.cpp @@ -103,7 +103,11 @@ void Sky::Draw(RenderContext& renderContext) psDesc.CullMode = CullMode::Inverted; psDesc.DepthWriteEnable = false; psDesc.DepthClipEnable = false; +#if FLAX_REVERSE_Z + psDesc.DepthFunc = ComparisonFunc::GreaterEqual; +#else psDesc.DepthFunc = ComparisonFunc::LessEqual; +#endif if (_psSky->Init(psDesc)) { diff --git a/Source/Engine/Renderer/DepthOfFieldPass.cpp b/Source/Engine/Renderer/DepthOfFieldPass.cpp index 2c3dc36f8..29807d440 100644 --- a/Source/Engine/Renderer/DepthOfFieldPass.cpp +++ b/Source/Engine/Renderer/DepthOfFieldPass.cpp @@ -271,8 +271,13 @@ void DepthOfFieldPass::Render(RenderContext& renderContext, GPUTexture*& frame, cbData.BokehTargetSize.Y = static_cast(bokehTargetHeight); // TODO: use projection matrix instead of this far and near stuff? +#if FLAX_REVERSE_Z + cbData.ProjectionAB.X = -nearPlane / (farPlane - nearPlane); + cbData.ProjectionAB.Y = (farPlane * nearPlane) / (farPlane - nearPlane); +#else cbData.ProjectionAB.X = farPlane / (farPlane - nearPlane); - cbData.ProjectionAB.Y = (-farPlane * nearPlane) / (farPlane - nearPlane); + cbData.ProjectionAB.Y = -(farPlane * nearPlane) / (farPlane - nearPlane); +#endif auto cb = shader->GetCB(0); context->UpdateCB(cb, &cbData); diff --git a/Source/Engine/Renderer/GBufferPass.cpp b/Source/Engine/Renderer/GBufferPass.cpp index 785aa970d..14e7ad1c3 100644 --- a/Source/Engine/Renderer/GBufferPass.cpp +++ b/Source/Engine/Renderer/GBufferPass.cpp @@ -442,7 +442,10 @@ bool GBufferPass::IsDebugView(ViewMode mode) void GBufferPass::SetInputs(const RenderView& view, ShaderGBufferData& gBuffer) { // GBuffer params: - // ViewInfo : x-1/Projection[0,0] y-1/Projection[1,1] z-(Far / (Far - Near) w-(-Far * Near) / (Far - Near) / Far) + // With reverse Z enabled: + // ViewInfo : x-1/Projection[0,0] y-1/Projection[1,1] z-(-(Near / (Far - Near)) w-((Far * Near) / (Far - Near) / Far) + // Otherwise: + // ViewInfo : x-1/Projection[0,0] y-1/Projection[1,1] z-(Far / (Far - Near)) w-(-(Far * Near) / (Far - Near) / Far) // ScreenSize : x-Width y-Height z-1 / Width w-1 / Height // ViewPos,ViewFar : x,y,z - world space view position w-Far // InvViewMatrix : inverse view matrix (4 rows by 4 columns) diff --git a/Source/Engine/Renderer/LightPass.cpp b/Source/Engine/Renderer/LightPass.cpp index 51461610e..1cad5fa31 100644 --- a/Source/Engine/Renderer/LightPass.cpp +++ b/Source/Engine/Renderer/LightPass.cpp @@ -90,7 +90,11 @@ bool LightPass::setupResources() psDesc.CullMode = CullMode::Normal; if (_psLightLocal.Create(psDesc, shader, "PS_LocalLight")) return true; +#if FLAX_REVERSE_Z + psDesc.DepthFunc = ComparisonFunc::Less; +#else psDesc.DepthFunc = ComparisonFunc::Greater; +#endif psDesc.CullMode = CullMode::Inverted; if (_psLightLocalInside.Create(psDesc, shader, "PS_LocalLight")) return true; @@ -107,7 +111,11 @@ bool LightPass::setupResources() psDesc.CullMode = CullMode::Normal; if (_psLightSky->Init(psDesc)) return true; +#if FLAX_REVERSE_Z + psDesc.DepthFunc = ComparisonFunc::Less; +#else psDesc.DepthFunc = ComparisonFunc::Greater; +#endif psDesc.CullMode = CullMode::Inverted; if (_psLightSkyInside->Init(psDesc)) return true; diff --git a/Source/Engine/Renderer/ShadowsPass.cpp b/Source/Engine/Renderer/ShadowsPass.cpp index 3361eed90..b21a37e9d 100644 --- a/Source/Engine/Renderer/ShadowsPass.cpp +++ b/Source/Engine/Renderer/ShadowsPass.cpp @@ -536,7 +536,11 @@ bool ShadowsPass::setupResources() psDesc.CullMode = CullMode::Normal; if (_psShadowPoint.Create(psDesc, shader, psLocalLight)) return true; +#if FLAX_REVERSE_Z + psDesc.DepthFunc = ComparisonFunc::Less; +#else psDesc.DepthFunc = ComparisonFunc::Greater; +#endif psDesc.CullMode = CullMode::Inverted; if (_psShadowPointInside.Create(psDesc, shader, psLocalLight)) return true; @@ -551,7 +555,11 @@ bool ShadowsPass::setupResources() psDesc.CullMode = CullMode::Normal; if (_psShadowSpot.Create(psDesc, shader, psLocalLight, 8)) return true; +#if FLAX_REVERSE_Z + psDesc.DepthFunc = ComparisonFunc::Less; +#else psDesc.DepthFunc = ComparisonFunc::Greater; +#endif psDesc.CullMode = CullMode::Inverted; if (_psShadowSpotInside.Create(psDesc, shader, psLocalLight, 8)) return true; @@ -1139,7 +1147,11 @@ 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 context->UpdateCB(quadShaderCB, &quadShaderData); context->BindCB(0, quadShaderCB); @@ -1590,14 +1602,7 @@ void ShadowsPass::RenderShadowMaps(RenderContextBatch& renderContextBatch) context->SetViewportAndScissors(Viewport(tile.StaticRectTile->X, tile.StaticRectTile->Y, tile.StaticRectTile->Width, tile.StaticRectTile->Height)); if (!shadows.ClearStaticShadowMapAtlas) { - // Color.r is used by PS_DepthClear in Quad shader to clear depth - quadShaderData.Color = Float4::One; - context->UpdateCB(quadShaderCB, &quadShaderData); - context->BindCB(0, quadShaderCB); - - // Clear tile depth - context->SetState(_psDepthClear); - context->DrawFullscreenTriangle(); + ClearShadowMapTile(context, quadShaderCB, quadShaderData); } // Draw objects depth diff --git a/Source/Engine/ShadersCompilation/ShaderCompiler.cpp b/Source/Engine/ShadersCompilation/ShaderCompiler.cpp index cfb08b925..ec4c54b02 100644 --- a/Source/Engine/ShadersCompilation/ShaderCompiler.cpp +++ b/Source/Engine/ShadersCompilation/ShaderCompiler.cpp @@ -249,6 +249,9 @@ bool ShaderCompiler::OnCompileBegin() const auto profile = GetProfile(); const auto featureLevel = RenderTools::GetFeatureLevel(profile); _globalMacros.Add({ "FEATURE_LEVEL", Numbers[(int32)featureLevel] }); +#if FLAX_REVERSE_Z + _globalMacros.Add({ "FLAX_REVERSE_Z", "1"}); +#endif return false; } diff --git a/Source/Shaders/Common.hlsl b/Source/Shaders/Common.hlsl index 457999398..b12cd4b71 100644 --- a/Source/Shaders/Common.hlsl +++ b/Source/Shaders/Common.hlsl @@ -4,22 +4,26 @@ #define __COMMON__ // Platform macros -#if !defined(DIRECTX) +#ifndef DIRECTX #define DIRECTX 0 #endif -#if !defined(OPENGL) +#ifndef OPENGL #define OPENGL 0 #endif -#if !defined(VULKAN) +#ifndef VULKAN #define VULKAN 0 #endif -#if defined(PLATFORM_PS4) +#ifdef PLATFORM_PS4 #include "./FlaxPlatforms/PS4/Shaders/PS4Common.hlsl" #endif -#if defined(PLATFORM_PS5) +#ifdef PLATFORM_PS5 #include "./FlaxPlatforms/PS5/Shaders/PS5Common.hlsl" #endif +#ifndef FLAX_REVERSE_Z +#define FLAX_REVERSE_Z 0 +#endif + // Feature levels #define FEATURE_LEVEL_ES2 0 #define FEATURE_LEVEL_ES3 1 @@ -165,7 +169,11 @@ float4 LoadTextureWGSL(Texture2D tex, float2 uv) // Structure that contains information about GBuffer struct GBufferData { - float4 ViewInfo; // x-1/Projection[0,0], y-1/Projection[1,1], z-(Far / (Far - Near), w-(-Far * Near) / (Far - Near) / Far) + // If reverse Z enabled: + // x-1/Projection[0,0], y-1/Projection[1,1], z-(-Near / (Far - Near)), w-((Far * Near) / (Far - Near) / Far) + // Otherwise: + // x-1/Projection[0,0], y-1/Projection[1,1], z-(Far / (Far - Near)), w-(-(Far * Near) / (Far - Near) / Far) + float4 ViewInfo; float4 ScreenSize; // x-Width, y-Height, z-1/Width, w-1/Height float3 ViewPos; // view position (in world space) float ViewFar; // view far plane distance (in world space) diff --git a/Source/Shaders/DebugDraw.shader b/Source/Shaders/DebugDraw.shader index 4f1aa9ba5..7dd52596d 100644 --- a/Source/Shaders/DebugDraw.shader +++ b/Source/Shaders/DebugDraw.shader @@ -41,7 +41,11 @@ float4 PS(VS2PS input) : SV_Target { float sceneDepthDeviceZ = SceneDepthTexture.Load(int3(input.Position.xy, 0)).r; float interpolatedDeviceZ = input.Position.z; +#if FLAX_REVERSE_Z + clip(interpolatedDeviceZ - sceneDepthDeviceZ); +#else clip(sceneDepthDeviceZ - interpolatedDeviceZ); +#endif } #endif diff --git a/Source/Shaders/SSR.hlsl b/Source/Shaders/SSR.hlsl index a5f6679b1..d5becb804 100644 --- a/Source/Shaders/SSR.hlsl +++ b/Source/Shaders/SSR.hlsl @@ -117,7 +117,11 @@ float3 TraceScreenSpaceReflection( { // Sample depth buffer and calculate depth difference float currSample = SAMPLE_RT_DEPTH(depthBuffer, currOffset.xy); - float depthDiff = currOffset.z - currSample; +#if FLAX_REVERSE_Z + depthDiff = currSample - currOffset.z; +#else + depthDiff = currOffset.z - currSample; +#endif // Check intersection if (depthDiff >= 0) diff --git a/Source/Shaders/Shadows.shader b/Source/Shaders/Shadows.shader index 275048333..1334a9108 100644 --- a/Source/Shaders/Shadows.shader +++ b/Source/Shaders/Shadows.shader @@ -47,7 +47,7 @@ float RayCastScreenSpaceShadow(GBufferData gBufferData, GBufferSample gBuffer, f float3 rayUV = rayCS.xyz / rayCS.w; rayUV.xy = rayUV.xy * float2(0.5, -0.5) + float2(0.5, 0.5); float sceneDepth = SampleDepth(gBufferData, rayUV.xy) * gBufferData.ViewFar; - float rayDepth = (gBufferData.ViewInfo.w / (rayUV.z - gBufferData.ViewInfo.z)) * gBufferData.ViewFar * 0.998; + float rayDepth = LinearizeZ(gBufferData, rayUV.z) * gBufferData.ViewFar * 0.998; float surfaceThickness = 0.035f + rayDepth * rayLength; float depthTestHardness = 0.005f; float lightAmount = saturate((rayDepth - sceneDepth) / depthTestHardness) * saturate((sceneDepth + surfaceThickness - rayDepth) / depthTestHardness); diff --git a/Source/Shaders/ShadowsCommon.hlsl b/Source/Shaders/ShadowsCommon.hlsl index f3ff9fd5b..e5e896bd2 100644 --- a/Source/Shaders/ShadowsCommon.hlsl +++ b/Source/Shaders/ShadowsCommon.hlsl @@ -74,9 +74,20 @@ float3 GetShadowPositionOffset(float offsetScale, float NoL, float3 normal) float CalculateSubsurfaceOcclusion(float opacity, float sceneDepth, float shadowMapDepth) { + // `sceneDepth` and `shadowMapDepth`are raw depths, so we have to flip them when reverse-z is enabled +#if FLAX_REVERSE_Z + float thickness = max(shadowMapDepth - sceneDepth, 0); +#else float thickness = max(sceneDepth - shadowMapDepth, 0); +#endif + float occlusion = 1 - saturate(thickness * lerp(1.0f, 100.0f, opacity)); + +#if FLAX_REVERSE_Z + return shadowMapDepth < 0.01f ? 1 : occlusion; +#else return shadowMapDepth > 0.99f ? 1 : occlusion; +#endif } float PostProcessShadow(ShadowData lightShadow, float shadow) diff --git a/Source/Tools/Flax.Build/Build/ProjectTarget.cs b/Source/Tools/Flax.Build/Build/ProjectTarget.cs index f67139a86..1ee3a0973 100644 --- a/Source/Tools/Flax.Build/Build/ProjectTarget.cs +++ b/Source/Tools/Flax.Build/Build/ProjectTarget.cs @@ -89,6 +89,13 @@ namespace Flax.Build options.ScriptingAPI.Defines.Add("PLATFORM_SDL"); } + if (!EngineConfiguration.WithTraditionalZ(options)) + { + // Add reverse-z definitions + options.CompileEnv.PreprocessorDefinitions.Add("FLAX_REVERSE_Z"); + options.ScriptingAPI.Defines.Add("FLAX_REVERSE_Z"); + } + // Add include paths for this and all referenced projects sources foreach (var project in Project.GetAllProjects()) { diff --git a/Source/Tools/Flax.Build/Configuration.cs b/Source/Tools/Flax.Build/Configuration.cs index 8a662df10..77ea2543f 100644 --- a/Source/Tools/Flax.Build/Configuration.cs +++ b/Source/Tools/Flax.Build/Configuration.cs @@ -306,6 +306,12 @@ namespace Flax.Build [CommandLine("useLargeWorlds", "1 to enable large worlds with 64-bit coordinates precision support in build (USE_LARGE_WORLDS=1)")] public static bool UseLargeWorlds = false; + /// + /// 1 to use traditional z buffer, or reversed z will be adopted by default. + /// + [CommandLine("noReverseZ", "1 to use traditional z buffer, or reversed z will be adopted by default.")] + public static bool NoReverseZ = false; + /// /// True if managed C# scripting should be enabled, otherwise false. Engine without C# is partially supported and can be used when porting to a new platform before implementing C# runtime on it. /// @@ -343,6 +349,12 @@ namespace Flax.Build return UseLargeWorlds; } + public static bool WithTraditionalZ(NativeCpp.BuildOptions options) + { + // Whether to use traditional z-buffer instead of reversed z + return NoReverseZ; + } + public static bool WithDotNet(NativeCpp.BuildOptions options) { return UseDotNet;