#include #include "../VolumeIntegrationSceneFixture.h" #include #include #include #include #include #include #include using namespace VolumeIntegrationTestUtils; namespace { constexpr const char* kD3D12Screenshot = "volume_occlusion_scene_d3d12.ppm"; constexpr const char* kOpenGLScreenshot = "volume_occlusion_scene_opengl.ppm"; constexpr const char* kVulkanScreenshot = "volume_occlusion_scene_vulkan.ppm"; const char* GetScreenshotFilename(RHIType backendType) { switch (backendType) { case RHIType::OpenGL: return kOpenGLScreenshot; case RHIType::Vulkan: return kVulkanScreenshot; case RHIType::D3D12: default: return kD3D12Screenshot; } } class VolumeOcclusionSceneTest : public VolumeIntegrationSceneFixture { protected: const char* GetSceneName() const override { return "VolumeOcclusionScene"; } void BuildScene() override { mVolumeMaterial = CreateVolumetricMaterial( "VolumeOcclusionMaterial", "Tests/Rendering/VolumeOcclusionScene/Volume.material", Vector4(1.0f, 1.0f, 1.0f, 1.0f), 0.24f, 0.75f, 2400.0f, 0.003f, Vector3(0.42f, 0.86f, 0.29f), 10.0f); ASSERT_NE(mVolumeMaterial, nullptr); mOccluderMaterial = CreateUnlitMaterial( "VolumeOccluderMaterial", "Tests/Rendering/VolumeOcclusionScene/Occluder.material", Vector4(0.92f, 0.36f, 0.18f, 1.0f)); ASSERT_NE(mOccluderMaterial, nullptr); mVolumeField = LoadCloudVolumeField(); ASSERT_NE(mVolumeField, nullptr); mCubeMesh = LoadBuiltinPrimitiveMesh(BuiltinPrimitiveType::Cube); ASSERT_TRUE(mCubeMesh.IsValid()); GameObject* cameraObject = mScene->CreateGameObject("MainCamera"); auto* camera = cameraObject->AddComponent(); camera->SetPrimary(true); camera->SetFieldOfView(45.0f); camera->SetNearClipPlane(0.1f); camera->SetFarClipPlane(5000.0f); camera->SetClearColor(XCEngine::Math::Color(0.03f, 0.04f, 0.06f, 1.0f)); cameraObject->GetTransform()->SetLocalPosition(Vector3(220.0f, 300.0f, -1200.0f)); cameraObject->GetTransform()->LookAt(Vector3(220.0f, 73.0f, 0.0f)); GameObject* volumeObject = mScene->CreateGameObject("CloudVolume"); auto* volumeRenderer = volumeObject->AddComponent(); volumeRenderer->SetVolumeField(mVolumeField); volumeRenderer->SetMaterial(mVolumeMaterial); volumeRenderer->SetCastShadows(false); volumeRenderer->SetReceiveShadows(false); GameObject* occluderObject = mScene->CreateGameObject("Occluder"); occluderObject->GetTransform()->SetLocalPosition(Vector3(220.0f, 88.0f, -900.0f)); occluderObject->GetTransform()->SetLocalScale(Vector3(450.0f, 320.0f, 12.0f)); auto* meshFilter = occluderObject->AddComponent(); auto* meshRenderer = occluderObject->AddComponent(); meshFilter->SetMesh(mCubeMesh); meshRenderer->SetMaterial(0, mOccluderMaterial); meshRenderer->SetCastShadows(false); meshRenderer->SetReceiveShadows(false); RenderSceneExtractor extractor; const RenderSceneData sceneData = extractor.Extract(*mScene, nullptr, kFrameWidth, kFrameHeight); ASSERT_EQ(sceneData.visibleItems.size(), 1u); ASSERT_EQ(sceneData.visibleVolumes.size(), 1u); } void ReleaseSceneResources() override { delete mVolumeField; mVolumeField = nullptr; delete mVolumeMaterial; mVolumeMaterial = nullptr; delete mOccluderMaterial; mOccluderMaterial = nullptr; mCubeMesh.Reset(); } private: Material* mVolumeMaterial = nullptr; Material* mOccluderMaterial = nullptr; VolumeField* mVolumeField = nullptr; ResourceHandle mCubeMesh; }; TEST_P(VolumeOcclusionSceneTest, RenderNanoVdbVolumeOcclusionScene) { const char* screenshotFilename = GetScreenshotFilename(GetBackendType()); RenderAndCompare(screenshotFilename, 0.0f); const RenderingIntegrationTestUtils::PpmImage image = RenderingIntegrationTestUtils::LoadPpmImage(screenshotFilename); RenderingIntegrationTestUtils::ExpectPixelLuminanceAtMost( image, 640u, 360u, 520, "occluder center should stay opaque"); RenderingIntegrationTestUtils::ExpectPixelLuminanceAtLeast( image, 1060u, 360u, 150, "cloud edge should remain visible"); } } // namespace INSTANTIATE_TEST_SUITE_P(D3D12, VolumeOcclusionSceneTest, ::testing::Values(XCEngine::RHI::RHIType::D3D12)); #if defined(XCENGINE_SUPPORT_OPENGL) INSTANTIATE_TEST_SUITE_P(OpenGL, VolumeOcclusionSceneTest, ::testing::Values(XCEngine::RHI::RHIType::OpenGL)); #endif #if defined(XCENGINE_SUPPORT_VULKAN) INSTANTIATE_TEST_SUITE_P(Vulkan, VolumeOcclusionSceneTest, ::testing::Values(XCEngine::RHI::RHIType::Vulkan)); #endif GTEST_API_ int main(int argc, char** argv) { return RunRenderingIntegrationTestMain(argc, argv); }