|
| 1 | +// |
| 2 | +// Copyright 2025 Pixar |
| 3 | +// |
| 4 | +// Licensed under the terms set forth in the LICENSE.txt file available at |
| 5 | +// https://openusd.org/license. |
| 6 | +// |
| 7 | +#include "pxr/pxr.h" |
| 8 | + |
| 9 | +#include "pxr/imaging/hd/tokens.h" |
| 10 | +#include "pxr/imaging/hd/unitTestDelegate.h" |
| 11 | +#include "pxr/imaging/hdSt/renderPass.h" |
| 12 | +#include "pxr/imaging/hdSt/unitTestGLDrawing.h" |
| 13 | +#include "pxr/imaging/hdSt/unitTestHelper.h" |
| 14 | + |
| 15 | +#include "pxr/base/gf/matrix4d.h" |
| 16 | +#include "pxr/base/gf/vec3d.h" |
| 17 | + |
| 18 | +#include "pxr/base/tf/errorMark.h" |
| 19 | + |
| 20 | +#include <iostream> |
| 21 | +#include <memory> |
| 22 | + |
| 23 | +// This test draws two almost identical cubes with identical transforms, in two |
| 24 | +// different passes. The only difference is that the first cube is white, while |
| 25 | +// the second is black. Since both cubes have exactly the same vertices, and |
| 26 | +// HdCmpFuncLess is used for depth, the black cube should be completely behind |
| 27 | +// the white cube (not even z-fighting). But if we give it even the smallest |
| 28 | +// amount of depth bias forward, it should instead completely replace the white |
| 29 | +// cube. |
| 30 | + |
| 31 | +PXR_NAMESPACE_USING_DIRECTIVE |
| 32 | + |
| 33 | +class HdSt_MyTestDriver : public HdSt_TestDriverBase<HdUnitTestDelegate> |
| 34 | +{ |
| 35 | +public: |
| 36 | + HdSt_MyTestDriver() |
| 37 | + { |
| 38 | + _renderPassStates = {std::dynamic_pointer_cast<HdStRenderPassState>( |
| 39 | + _GetRenderDelegate()->CreateRenderPassState()), |
| 40 | + std::dynamic_pointer_cast<HdStRenderPassState>( |
| 41 | + _GetRenderDelegate()->CreateRenderPassState())}; |
| 42 | + |
| 43 | + _renderPassStates[0]->SetDepthFunc(HdCmpFuncLess); |
| 44 | + _renderPassStates[0]->SetCullStyle(HdCullStyleNothing); |
| 45 | + _renderPassStates[0]->SetDepthBiasUseDefault(false); |
| 46 | + |
| 47 | + _renderPassStates[1]->SetDepthFunc(HdCmpFuncLess); |
| 48 | + _renderPassStates[1]->SetCullStyle(HdCullStyleNothing); |
| 49 | + _renderPassStates[1]->SetDepthBiasUseDefault(false); |
| 50 | + _renderPassStates[1]->SetDepthBias(-1, 0); |
| 51 | + |
| 52 | + _Init(); |
| 53 | + |
| 54 | + const HdRprimCollection collections[] = { |
| 55 | + HdRprimCollection(HdTokens->geometry, |
| 56 | + HdReprSelector(HdReprTokens->smoothHull), SdfPath("/white")), |
| 57 | + HdRprimCollection(HdTokens->geometry, |
| 58 | + HdReprSelector(HdReprTokens->smoothHull), SdfPath("/black")), |
| 59 | + }; |
| 60 | + |
| 61 | + for (size_t i = 0; i < std::size(collections); i++) { |
| 62 | + _renderPasses.push_back(std::make_shared<HdSt_RenderPass>( |
| 63 | + &GetDelegate().GetRenderIndex(), collections[i])); |
| 64 | + } |
| 65 | + } |
| 66 | + |
| 67 | + void Draw(bool enableDepthBias) |
| 68 | + { |
| 69 | + // The unit test AOV setup sets a clear value, which we need to remove |
| 70 | + // so we can do a second pass on the same contents. |
| 71 | + auto aovs = _renderPassStates[1]->GetAovBindings(); |
| 72 | + for (auto& aov : aovs) { |
| 73 | + aov.clearValue = VtValue{}; |
| 74 | + } |
| 75 | + _renderPassStates[1]->SetAovBindings(aovs); |
| 76 | + |
| 77 | + _renderPassStates[1]->SetDepthBiasEnabled(enableDepthBias); |
| 78 | + |
| 79 | + HdTaskSharedPtrVector tasks; |
| 80 | + for (size_t i = 0; i < _renderPassStates.size(); i++) { |
| 81 | + tasks.push_back(std::make_shared<HdSt_DrawTask>(_renderPasses[i], |
| 82 | + _renderPassStates[i], |
| 83 | + TfTokenVector{HdRenderTagTokens->geometry})); |
| 84 | + } |
| 85 | + _GetEngine()->Execute(&GetDelegate().GetRenderIndex(), &tasks); |
| 86 | + } |
| 87 | +}; |
| 88 | + |
| 89 | +class My_TestGLDrawing : public HdSt_UnitTestGLDrawing |
| 90 | +{ |
| 91 | +public: |
| 92 | + My_TestGLDrawing() |
| 93 | + { |
| 94 | + SetCameraRotate(60.0f, 0.0f); |
| 95 | + SetCameraTranslate(GfVec3f(0, 0, -20.0f)); |
| 96 | + } |
| 97 | + |
| 98 | + void InitTest() override; |
| 99 | + void DrawTest() override; |
| 100 | + void OffscreenTest() override; |
| 101 | + void Present(uint32_t framebuffer) override; |
| 102 | + |
| 103 | +protected: |
| 104 | + void ParseArgs(int argc, char* argv[]) override; |
| 105 | + |
| 106 | + void _Draw(bool enableDepthBias = false); |
| 107 | + |
| 108 | +private: |
| 109 | + std::unique_ptr<HdSt_MyTestDriver> _driver; |
| 110 | +}; |
| 111 | + |
| 112 | +//////////////////////////////////////////////////////////////// |
| 113 | + |
| 114 | +void |
| 115 | +My_TestGLDrawing::InitTest() |
| 116 | +{ |
| 117 | + std::cout << "My_TestGLDrawing::InitTest()" << std::endl; |
| 118 | + |
| 119 | + _driver = std::make_unique<HdSt_MyTestDriver>(); |
| 120 | + _driver->SetClearColor(GfVec4f(0.1f, 0.1f, 0.1f, 1.0f)); |
| 121 | + _driver->SetClearDepth(1.0f); |
| 122 | + _driver->SetupAovs(GetWidth(), GetHeight()); |
| 123 | + |
| 124 | + const auto cubeTransform = GfMatrix4f(1.0f).SetScale(4.0f) * |
| 125 | + GfMatrix4f(1.0f).SetRotate(GfRotation(GfVec3f(0, 0, 1), 45)); |
| 126 | + |
| 127 | + HdUnitTestDelegate& delegate = _driver->GetDelegate(); |
| 128 | + const SdfPath whiteCube{"/white/cube"}; |
| 129 | + delegate.AddCube(whiteCube, cubeTransform, false, SdfPath(), |
| 130 | + PxOsdOpenSubdivTokens->none); |
| 131 | + delegate.UpdatePrimvarValue( |
| 132 | + whiteCube, HdTokens->displayColor, VtValue(GfVec3f(1))); |
| 133 | + |
| 134 | + const SdfPath blackCube{"/black/cube"}; |
| 135 | + delegate.AddCube(blackCube, cubeTransform, false, SdfPath(), |
| 136 | + PxOsdOpenSubdivTokens->none); |
| 137 | + delegate.UpdatePrimvarValue( |
| 138 | + blackCube, HdTokens->displayColor, VtValue(GfVec3f(0))); |
| 139 | +} |
| 140 | + |
| 141 | +void |
| 142 | +My_TestGLDrawing::_Draw(bool enableDepthBias) |
| 143 | +{ |
| 144 | + int width = GetWidth(), height = GetHeight(); |
| 145 | + GfMatrix4d viewMatrix = GetViewMatrix(); |
| 146 | + GfMatrix4d projMatrix = GetProjectionMatrix(); |
| 147 | + |
| 148 | + _driver->SetCamera(viewMatrix, projMatrix, |
| 149 | + CameraUtilFraming(GfRect2i(GfVec2i(0, 0), width, height))); |
| 150 | + |
| 151 | + _driver->UpdateAovDimensions(width, height); |
| 152 | + |
| 153 | + _driver->Draw(enableDepthBias); |
| 154 | +} |
| 155 | + |
| 156 | +void |
| 157 | +My_TestGLDrawing::DrawTest() |
| 158 | +{ |
| 159 | + _Draw(); |
| 160 | +} |
| 161 | + |
| 162 | +void |
| 163 | +My_TestGLDrawing::OffscreenTest() |
| 164 | +{ |
| 165 | + _Draw(/*enableDepthBias=*/false); |
| 166 | + _driver->WriteToFile("color", "testHdStDepthBias_disabled.png"); |
| 167 | + |
| 168 | + _Draw(/*enableDepthBias=*/true); |
| 169 | + _driver->WriteToFile("color", "testHdStDepthBias_enabled.png"); |
| 170 | +} |
| 171 | + |
| 172 | +void |
| 173 | +My_TestGLDrawing::Present(uint32_t framebuffer) |
| 174 | +{ |
| 175 | + _driver->Present(GetWidth(), GetHeight(), framebuffer); |
| 176 | +} |
| 177 | + |
| 178 | +void |
| 179 | +My_TestGLDrawing::ParseArgs(int argc, char* argv[]) |
| 180 | +{ |
| 181 | +} |
| 182 | + |
| 183 | +void |
| 184 | +BasicTest(int argc, char* argv[]) |
| 185 | +{ |
| 186 | + My_TestGLDrawing driver; |
| 187 | + driver.RunTest(argc, argv); |
| 188 | +} |
| 189 | + |
| 190 | +int |
| 191 | +main(int argc, char* argv[]) |
| 192 | +{ |
| 193 | + TfErrorMark mark; |
| 194 | + |
| 195 | + BasicTest(argc, argv); |
| 196 | + |
| 197 | + if (mark.IsClean()) { |
| 198 | + std::cout << "OK" << std::endl; |
| 199 | + return EXIT_SUCCESS; |
| 200 | + } else { |
| 201 | + std::cout << "FAILED" << std::endl; |
| 202 | + return EXIT_FAILURE; |
| 203 | + } |
| 204 | +} |
0 commit comments