Skip to content

Commit 8993312

Browse files
Hydrogent: compute precise depth bounds for scene depth overlay
1 parent 77a7a6d commit 8993312

File tree

8 files changed

+325
-4
lines changed

8 files changed

+325
-4
lines changed

Components/interface/DepthRangeCalculator.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,11 @@ class DepthRangeCalculator
140140
float fSceneFarZ = 0;
141141
float fSceneNearDepth = 0;
142142
float fSceneFarDepth = 0;
143+
144+
constexpr operator bool() const
145+
{
146+
return fSceneNearDepth > 0 && fSceneFarDepth > 0;
147+
}
143148
};
144149

145150
/// Returns the depth range read back to the CPU.

Hydrogent/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ set(SOURCE
4141
src/Tasks/HnBeginFrameTask.cpp
4242
src/Tasks/HnRenderShadowsTask.cpp
4343
src/Tasks/HnBeginOITPassTask.cpp
44+
src/Tasks/HnComputeDepthBoundsTask.cpp
4445
src/Tasks/HnEndOITPassTask.cpp
4546
src/Tasks/HnBeginMainPassTask.cpp
4647
src/Tasks/HnRenderRprimsTask.cpp
@@ -91,6 +92,7 @@ set(INTERFACE
9192
interface/Tasks/HnBeginMainPassTask.hpp
9293
interface/Tasks/HnRenderShadowsTask.hpp
9394
interface/Tasks/HnBeginOITPassTask.hpp
95+
interface/Tasks/HnComputeDepthBoundsTask.hpp
9496
interface/Tasks/HnEndOITPassTask.hpp
9597
interface/Tasks/HnRenderRprimsTask.hpp
9698
interface/Tasks/HnRenderEnvMapTask.hpp
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright 2025 Diligent Graphics LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* In no event and under no legal theory, whether in tort (including negligence),
17+
* contract, or otherwise, unless required by applicable law (such as deliberate
18+
* and grossly negligent acts) or agreed to in writing, shall any Contributor be
19+
* liable for any damages, including any direct, indirect, special, incidental,
20+
* or consequential damages of any character arising as a result of this License or
21+
* out of the use or inability to use the software (including but not limited to damages
22+
* for loss of goodwill, work stoppage, computer failure or malfunction, or any and
23+
* all other commercial damages or losses), even if such Contributor has been advised
24+
* of the possibility of such damages.
25+
*/
26+
27+
#pragma once
28+
29+
#include <memory>
30+
#include <array>
31+
32+
#include "HnTask.hpp"
33+
34+
#include "../../../../DiligentCore/Graphics/GraphicsEngine/interface/Buffer.h"
35+
#include "../../../../DiligentCore/Graphics/GraphicsEngine/interface/ShaderResourceBinding.h"
36+
#include "../../../../DiligentCore/Common/interface/RefCntAutoPtr.hpp"
37+
38+
namespace Diligent
39+
{
40+
41+
class DepthRangeCalculator;
42+
43+
namespace USD
44+
{
45+
46+
struct HnFrameRenderTargets;
47+
48+
struct HnComputeDepthBoundsTaskParams
49+
{
50+
constexpr bool operator==(const HnComputeDepthBoundsTaskParams& rhs) const
51+
{
52+
return true;
53+
}
54+
constexpr bool operator!=(const HnComputeDepthBoundsTaskParams& rhs) const
55+
{
56+
return !(*this == rhs);
57+
}
58+
};
59+
60+
/// Computes scene depth bounds
61+
class HnComputeDepthBoundsTask final : public HnTask
62+
{
63+
public:
64+
HnComputeDepthBoundsTask(pxr::HdSceneDelegate* ParamsDelegate, const pxr::SdfPath& Id);
65+
~HnComputeDepthBoundsTask();
66+
67+
virtual void Sync(pxr::HdSceneDelegate* Delegate,
68+
pxr::HdTaskContext* TaskCtx,
69+
pxr::HdDirtyBits* DirtyBits) override final;
70+
71+
virtual void Prepare(pxr::HdTaskContext* TaskCtx,
72+
pxr::HdRenderIndex* RenderIndex) override final;
73+
74+
virtual void Execute(pxr::HdTaskContext* TaskCtx) override final;
75+
76+
virtual bool IsActive(pxr::HdRenderIndex& RenderIndex) const override final;
77+
78+
private:
79+
pxr::HdRenderIndex* m_RenderIndex = nullptr;
80+
81+
const HnFrameRenderTargets* m_FrameTargets = nullptr; // Set in Prepare()
82+
Uint32 m_FrameRenderTargetsVersion = ~0u;
83+
84+
std::unique_ptr<DepthRangeCalculator> m_DepthRangeCalculator;
85+
86+
// Two SRBs for ping-ponging between depth buffers.
87+
std::array<RefCntAutoPtr<IShaderResourceBinding>, 2> m_ComputeDepthRangeSRBs{};
88+
};
89+
90+
} // namespace USD
91+
92+
} // namespace Diligent

Hydrogent/interface/Tasks/HnTaskManager.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ class HnTaskManager
7474
static constexpr TaskUID TaskUID_RenderBoundBox = 0x1e7e47f37e6445b4;
7575
static constexpr TaskUID TaskUID_ReadRprimId = 0x199572fe7ff144ef;
7676
static constexpr TaskUID TaskUID_ProcessSelection = 0x87ef181ec6d4cf83;
77+
static constexpr TaskUID TaskUID_ComputeDepthBounds = 0xff2b5caa64354557;
7778
static constexpr TaskUID TaskUID_PostProcess = 0x1f5367e65d034500;
7879

7980
HnTaskManager(pxr::HdRenderIndex& RenderIndex,
@@ -123,6 +124,7 @@ class HnTaskManager
123124
/// * Renders only selected Rprims with the additive material tag (depth only)
124125
/// - RenderRprimsTranslucentSelected
125126
/// * Renders only selected Rprims with the translucent material tag (depth only)
127+
/// - ComputeDepthBounds
126128
/// - ReadRprimId
127129
/// - ProcessSelection
128130
/// * Generates the closest selected location texture using the Jump-Flood algorithm
@@ -148,6 +150,7 @@ class HnTaskManager
148150
/// | RenderRprimsTranslucentMeshId | V | V | | V | MV, N | | V |
149151
/// | RenderRprimsAdditiveSelected | V | | | | | V | |
150152
/// | RenderRprimsTranslucentSelected | V | | | | | V | |
153+
/// | ComputeDepthBounds | | | | | | | |
151154
/// | ReadRprimId | | | | | | | |
152155
/// | ProcessSelection | | | | | | | |
153156
/// | PostProcess | | | | | | | |
@@ -265,6 +268,7 @@ class HnTaskManager
265268
void CreateEndOITPassTask();
266269
void CreateReadRprimIdTask();
267270
void CreateCopySelectionDepthTask();
271+
void CreateComputeDepthBoundsTask();
268272
void CreateProcessSelectionTask();
269273
void CreatePostProcessTask();
270274

Hydrogent/shaders/HnPostProcess.psh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,19 @@ void main(in FullScreenTriangleVSOutput VSOut,
4343
float4 Pos = VSOut.f4PixelPos;
4444

4545
Color = g_ColorBuffer.Load(int3(Pos.xy, 0));
46+
if (g_Frame.Renderer.DebugView == DEBUG_VIEW_SCENE_DEPTH)
47+
{
48+
// The overlay was rendered with Scene Range == Camera Range.
49+
// At the end of the frame, we computed the accurate scene depth range in HnComputeDepthBoundsTask,
50+
// so now we can use it to rescale the depth value.
51+
float RelZ = Color.r;
52+
53+
RelZ = RelZ * (g_Frame.Camera.fFarPlaneZ - g_Frame.Camera.fNearPlaneZ) + g_Frame.Camera.fNearPlaneZ;
54+
RelZ = (RelZ - g_Frame.Camera.fSceneNearZ) / max(g_Frame.Camera.fSceneFarZ - g_Frame.Camera.fSceneNearZ, 1e-6);
55+
RelZ = saturate(RelZ);
56+
Color.rgb = float3(RelZ, RelZ, RelZ);
57+
}
58+
4659
float Opacity = 1.0 - Color.a;
4760

4861
float SSRScale = g_Attribs.SSRScale * Opacity;
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
/*
2+
* Copyright 2025 Diligent Graphics LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* In no event and under no legal theory, whether in tort (including negligence),
17+
* contract, or otherwise, unless required by applicable law (such as deliberate
18+
* and grossly negligent acts) or agreed to in writing, shall any Contributor be
19+
* liable for any damages, including any direct, indirect, special, incidental,
20+
* or consequential damages of any character arising as a result of this License or
21+
* out of the use or inability to use the software (including but not limited to damages
22+
* for loss of goodwill, work stoppage, computer failure or malfunction, or any and
23+
* all other commercial damages or losses), even if such Contributor has been advised
24+
* of the possibility of such damages.
25+
*/
26+
27+
#include "Tasks/HnComputeDepthBoundsTask.hpp"
28+
#include "HnRenderDelegate.hpp"
29+
#include "ScopedDebugGroup.hpp"
30+
#include "HnRenderParam.hpp"
31+
#include "DepthRangeCalculator.hpp"
32+
#include "HnFrameRenderTargets.hpp"
33+
#include "HnTokens.hpp"
34+
35+
namespace Diligent
36+
{
37+
38+
namespace HLSL
39+
{
40+
#include "Shaders/Common/public/BasicStructures.fxh"
41+
#include "Shaders/Common/private/ComputeDepthRangeStructs.fxh"
42+
} // namespace HLSL
43+
44+
namespace USD
45+
{
46+
47+
HnComputeDepthBoundsTask::HnComputeDepthBoundsTask(pxr::HdSceneDelegate* ParamsDelegate, const pxr::SdfPath& Id) :
48+
HnTask{Id}
49+
{
50+
}
51+
52+
HnComputeDepthBoundsTask::~HnComputeDepthBoundsTask()
53+
{
54+
}
55+
56+
void HnComputeDepthBoundsTask::Sync(pxr::HdSceneDelegate* Delegate,
57+
pxr::HdTaskContext* TaskCtx,
58+
pxr::HdDirtyBits* DirtyBits)
59+
{
60+
*DirtyBits = pxr::HdChangeTracker::Clean;
61+
}
62+
63+
bool HnComputeDepthBoundsTask::IsActive(pxr::HdRenderIndex& RenderIndex) const
64+
{
65+
pxr::HdRenderDelegate* RenderDelegate = RenderIndex.GetRenderDelegate();
66+
const HnRenderParam* RenderParam = static_cast<const HnRenderParam*>(RenderDelegate->GetRenderParam());
67+
const HN_RENDER_MODE RenderMode = RenderParam->GetRenderMode();
68+
const PBR_Renderer::DebugViewType DebugView = RenderParam->GetDebugView();
69+
70+
// Only run this task when scene depth debug view is enabled
71+
return RenderMode == HN_RENDER_MODE_SOLID && DebugView == PBR_Renderer::DebugViewType::SceneDepth;
72+
}
73+
74+
void HnComputeDepthBoundsTask::Prepare(pxr::HdTaskContext* TaskCtx,
75+
pxr::HdRenderIndex* RenderIndex)
76+
{
77+
m_RenderIndex = RenderIndex;
78+
79+
m_FrameTargets = GetFrameRenderTargets(TaskCtx);
80+
if (m_FrameTargets == nullptr)
81+
{
82+
UNEXPECTED("Framebuffer targets are null");
83+
return;
84+
}
85+
86+
if (m_FrameTargets->Version != m_FrameRenderTargetsVersion)
87+
{
88+
m_FrameRenderTargetsVersion = m_FrameTargets->Version;
89+
m_ComputeDepthRangeSRBs = {};
90+
}
91+
92+
HnRenderDelegate* RenderDelegate = static_cast<HnRenderDelegate*>(RenderIndex->GetRenderDelegate());
93+
const HnRenderParam* RenderParam = static_cast<const HnRenderParam*>(RenderDelegate->GetRenderParam());
94+
95+
if (!m_DepthRangeCalculator)
96+
{
97+
DepthRangeCalculator::CreateInfo DepthRangeCalcCI;
98+
DepthRangeCalcCI.pDevice = RenderDelegate->GetDevice();
99+
DepthRangeCalcCI.pStateCache = RenderDelegate->GetRenderStateCache();
100+
DepthRangeCalcCI.PackMatrixRowMajor = RenderDelegate->GetUSDRenderer()->GetSettings().PackMatrixRowMajor;
101+
DepthRangeCalcCI.AsyncShaders = RenderParam->GetConfig().AsyncShaderCompilation;
102+
103+
try
104+
{
105+
m_DepthRangeCalculator = std::make_unique<DepthRangeCalculator>(DepthRangeCalcCI);
106+
}
107+
catch (const std::exception& e)
108+
{
109+
UNEXPECTED("Failed to create DepthRangeCalculator: ", e.what());
110+
}
111+
catch (...)
112+
{
113+
UNEXPECTED("Failed to create DepthRangeCalculator");
114+
}
115+
}
116+
}
117+
118+
void HnComputeDepthBoundsTask::Execute(pxr::HdTaskContext* TaskCtx)
119+
{
120+
if (m_RenderIndex == nullptr)
121+
{
122+
UNEXPECTED("Render index is null. This likely indicates that Prepare() has not been called.");
123+
return;
124+
}
125+
126+
if (!m_DepthRangeCalculator)
127+
{
128+
UNEXPECTED("DepthRangeCalculator is null. This likely indicates that Prepare() has not been called.");
129+
return;
130+
}
131+
132+
if (!m_DepthRangeCalculator->IsReady())
133+
{
134+
return;
135+
}
136+
137+
ITexture* pDepth = m_FrameTargets->DepthDSV != nullptr ? m_FrameTargets->DepthDSV->GetTexture() : nullptr;
138+
if (pDepth == nullptr)
139+
{
140+
UNEXPECTED("Depth stencil view is null");
141+
return;
142+
}
143+
144+
ITextureView* pDepthSRV = pDepth->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE);
145+
if (pDepthSRV == nullptr)
146+
{
147+
UNEXPECTED("Depth SRV is null");
148+
return;
149+
}
150+
151+
HnRenderDelegate* RenderDelegate = static_cast<HnRenderDelegate*>(m_RenderIndex->GetRenderDelegate());
152+
const HnRenderParam* RenderParam = static_cast<const HnRenderParam*>(RenderDelegate->GetRenderParam());
153+
IDeviceContext* pCtx = RenderDelegate->GetDeviceContext();
154+
IBuffer* pFrameAttribsCB = RenderDelegate->GetFrameAttribsCB();
155+
156+
RefCntAutoPtr<IShaderResourceBinding>& ComputeDepthRangeSRB = m_ComputeDepthRangeSRBs[RenderParam->GetFrameNumber() & 0x01];
157+
if (!ComputeDepthRangeSRB)
158+
{
159+
ComputeDepthRangeSRB = m_DepthRangeCalculator->CreateSRB(pDepthSRV, pFrameAttribsCB);
160+
}
161+
162+
ScopedDebugGroup DebugGroup{pCtx, "Compute Depth Bounds"};
163+
164+
const TextureDesc& DepthDesc = pDepth->GetDesc();
165+
166+
DepthRangeCalculator::ComputeRangeAttribs Attribs;
167+
Attribs.pContext = pCtx;
168+
Attribs.pSRB = ComputeDepthRangeSRB;
169+
Attribs.Width = DepthDesc.Width;
170+
Attribs.Height = DepthDesc.Height;
171+
m_DepthRangeCalculator->ComputeRange(Attribs);
172+
173+
// Copy the depth range to the frame attributes constant buffer
174+
if (IBuffer* pDepthRangeBuffer = m_DepthRangeCalculator->GetDepthRangeBuffer())
175+
{
176+
pCtx->CopyBuffer(pDepthRangeBuffer, 0, RESOURCE_STATE_TRANSITION_MODE_TRANSITION,
177+
pFrameAttribsCB, offsetof(HLSL::CameraAttribs, fSceneNearZ), sizeof(HLSL::DepthRangeI), RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
178+
179+
StateTransitionDesc Barrier{pFrameAttribsCB, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_CONSTANT_BUFFER, STATE_TRANSITION_FLAG_UPDATE_STATE};
180+
pCtx->TransitionResourceStates(1, &Barrier);
181+
}
182+
else
183+
{
184+
UNEXPECTED("Depth range buffer is null");
185+
}
186+
}
187+
188+
} // namespace USD
189+
190+
} // namespace Diligent

Hydrogent/src/Tasks/HnPostProcessTask.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ void HnPostProcessTask::PostProcessingTechnique::PreparePSO(TEXTURE_FORMAT RTVFo
202202
ShaderMacroHelper Macros;
203203
Macros.Add("CONVERT_OUTPUT_TO_SRGB", ConvertOutputToSRGB);
204204
Macros.Add("TONE_MAPPING_MODE", ToneMappingMode);
205+
Macros.Add("DEBUG_VIEW_SCENE_DEPTH", static_cast<int>(PBR_Renderer::DebugViewType::SceneDepth));
205206
if (GridFeatureFlags != CoordinateGridRenderer::FEATURE_FLAG_NONE)
206207
{
207208
Macros.Add("ENABLE_GRID", 1);

0 commit comments

Comments
 (0)