chore: checkpoint current workspace changes

This commit is contained in:
2026-04-11 22:14:02 +08:00
parent 3e55f8c204
commit 8848cfd958
227 changed files with 34027 additions and 6711 deletions

File diff suppressed because one or more lines are too long

View File

@@ -9,6 +9,7 @@
#include <XCEngine/Components/CameraComponent.h>
#include <XCEngine/Components/GameObject.h>
#include <XCEngine/Components/GaussianSplatRendererComponent.h>
#include <XCEngine/Core/Asset/AssetDatabase.h>
#include <XCEngine/Core/Asset/IResource.h>
#include <XCEngine/Core/Asset/ResourceManager.h>
#include <XCEngine/Core/Math/Color.h>
@@ -16,6 +17,7 @@
#include <XCEngine/Rendering/Execution/SceneRenderer.h>
#include <XCEngine/Rendering/RenderContext.h>
#include <XCEngine/Rendering/RenderSurface.h>
#include <XCEngine/Resources/GaussianSplat/GaussianSplatArtifactIO.h>
#include <XCEngine/Resources/GaussianSplat/GaussianSplat.h>
#include <XCEngine/Resources/Material/Material.h>
#include <XCEngine/Resources/BuiltinResources.h>
@@ -49,6 +51,9 @@ constexpr const char* kVulkanScreenshot = "gaussian_splat_scene_vulkan.ppm";
constexpr uint32_t kFrameWidth = 1280;
constexpr uint32_t kFrameHeight = 720;
constexpr uint32_t kBaselineSubsetSplatCount = 65536u;
constexpr const char* kSubsetGaussianSplatAssetPath = "Assets/room_subset.xcgsplat";
constexpr float kTargetSceneExtent = 4.0f;
constexpr float kGaussianPointScale = 3.00f;
XCEngine::Core::uint16 FloatToHalfBits(float value) {
uint32_t bits = 0u;
@@ -329,7 +334,7 @@ private:
RHITexture* m_depthTexture = nullptr;
RHIResourceView* m_depthView = nullptr;
ResourceHandle<GaussianSplat> m_gaussianSplat;
GaussianSplat* m_subsetGaussianSplat = nullptr;
ResourceHandle<GaussianSplat> m_subsetGaussianSplat;
Material* m_material = nullptr;
};
@@ -394,8 +399,7 @@ void GaussianSplatSceneTest::TearDown() {
delete m_material;
m_material = nullptr;
delete m_subsetGaussianSplat;
m_subsetGaussianSplat = nullptr;
m_subsetGaussianSplat.Reset();
m_gaussianSplat.Reset();
ResourceManager& manager = ResourceManager::Get();
@@ -430,25 +434,53 @@ void GaussianSplatSceneTest::PrepareRuntimeProject() {
manager.Initialize();
manager.SetResourceRoot(m_projectRoot.string().c_str());
m_gaussianSplat = manager.Load<GaussianSplat>("Assets/room.ply");
AssetDatabase database;
database.Initialize(m_projectRoot.string().c_str());
AssetDatabase::ResolvedAsset roomResolve;
ASSERT_TRUE(database.EnsureArtifact("Assets/room.ply", ResourceType::GaussianSplat, roomResolve));
ASSERT_TRUE(roomResolve.artifactReady);
ASSERT_FALSE(roomResolve.artifactMainPath.Empty());
m_gaussianSplat = manager.Load<GaussianSplat>(roomResolve.artifactMainPath);
ASSERT_TRUE(m_gaussianSplat.IsValid());
ASSERT_NE(m_gaussianSplat.Get(), nullptr);
ASSERT_TRUE(m_gaussianSplat->IsValid());
ASSERT_GT(m_gaussianSplat->GetSplatCount(), 0u);
ASSERT_EQ(m_gaussianSplat->GetSHOrder(), 3u);
m_subsetGaussianSplat = CreateGaussianSplatSubset(
*m_gaussianSplat.Get(),
kBaselineSubsetSplatCount,
"Tests/Rendering/GaussianSplatScene/RoomSubset.xcgsplat");
ASSERT_NE(m_subsetGaussianSplat, nullptr);
std::unique_ptr<GaussianSplat> subsetGaussianSplat(
CreateGaussianSplatSubset(
*m_gaussianSplat.Get(),
kBaselineSubsetSplatCount,
kSubsetGaussianSplatAssetPath));
ASSERT_NE(subsetGaussianSplat, nullptr);
ASSERT_TRUE(subsetGaussianSplat->IsValid());
ASSERT_GT(subsetGaussianSplat->GetSplatCount(), 0u);
ASSERT_EQ(subsetGaussianSplat->GetSHOrder(), 3u);
const std::filesystem::path subsetArtifactPath = assetsDir / "room_subset.xcgsplat";
XCEngine::Containers::String subsetWriteError;
ASSERT_TRUE(WriteGaussianSplatArtifactFile(
subsetArtifactPath.string().c_str(),
*subsetGaussianSplat,
&subsetWriteError)) << subsetWriteError.CStr();
m_subsetGaussianSplat = manager.Load<GaussianSplat>(
XCEngine::Containers::String(subsetArtifactPath.string().c_str()));
ASSERT_TRUE(m_subsetGaussianSplat.IsValid());
ASSERT_NE(m_subsetGaussianSplat.Get(), nullptr);
ASSERT_TRUE(m_subsetGaussianSplat->IsValid());
ASSERT_GT(m_subsetGaussianSplat->GetSplatCount(), 0u);
ASSERT_EQ(m_subsetGaussianSplat->GetSHOrder(), 3u);
ASSERT_NE(m_subsetGaussianSplat->FindSection(GaussianSplatSectionType::Chunks), nullptr);
database.Shutdown();
}
void GaussianSplatSceneTest::BuildScene() {
ASSERT_NE(m_scene, nullptr);
ASSERT_NE(m_subsetGaussianSplat, nullptr);
ASSERT_TRUE(m_subsetGaussianSplat.IsValid());
m_material = new Material();
IResource::ConstructParams params = {};
@@ -458,7 +490,7 @@ void GaussianSplatSceneTest::BuildScene() {
m_material->Initialize(params);
m_material->SetShader(ResourceManager::Get().Load<Shader>(GetBuiltinGaussianSplatShaderPath()));
m_material->SetRenderQueue(MaterialRenderQueue::Transparent);
m_material->SetFloat("_PointScale", 1.0f);
m_material->SetFloat("_PointScale", kGaussianPointScale);
m_material->SetFloat("_OpacityScale", 1.0f);
GameObject* cameraObject = m_scene->CreateGameObject("MainCamera");
@@ -480,10 +512,10 @@ void GaussianSplatSceneTest::BuildScene() {
const float sizeY = std::max(boundsMax.y - boundsMin.y, 0.001f);
const float sizeZ = std::max(boundsMax.z - boundsMin.z, 0.001f);
const float maxExtent = std::max(sizeX, std::max(sizeY, sizeZ));
const float uniformScale = 3.0f / maxExtent;
const float uniformScale = kTargetSceneExtent / maxExtent;
GameObject* root = m_scene->CreateGameObject("GaussianSplatRoot");
root->GetTransform()->SetLocalPosition(Vector3(0.0f, -0.35f, 3.2f));
root->GetTransform()->SetLocalPosition(Vector3::Zero());
root->GetTransform()->SetLocalScale(Vector3(uniformScale, uniformScale, uniformScale));
GameObject* splatObject = m_scene->CreateGameObject("RoomGaussianSplat");
@@ -491,10 +523,11 @@ void GaussianSplatSceneTest::BuildScene() {
splatObject->GetTransform()->SetLocalPosition(Vector3(-center.x, -center.y, -center.z));
auto* splatRenderer = splatObject->AddComponent<GaussianSplatRendererComponent>();
splatRenderer->SetGaussianSplat(m_subsetGaussianSplat);
splatRenderer->SetGaussianSplat(m_subsetGaussianSplat.Get());
splatRenderer->SetMaterial(m_material);
splatRenderer->SetCastShadows(false);
splatRenderer->SetReceiveShadows(false);
cameraObject->GetTransform()->SetLocalPosition(Vector3(0.0f, 1.0f, 1.0f));
}
RHIResourceView* GaussianSplatSceneTest::GetCurrentBackBufferView() {
@@ -551,7 +584,7 @@ TEST_P(GaussianSplatSceneTest, RenderRoomGaussianSplatScene) {
ASSERT_NE(commandQueue, nullptr);
ASSERT_NE(swapChain, nullptr);
constexpr int kTargetFrameCount = 1;
constexpr int kTargetFrameCount = 2;
const char* screenshotFilename = GetScreenshotFilename(GetBackendType());
for (int frameCount = 0; frameCount <= kTargetFrameCount; ++frameCount) {

View File

@@ -67,5 +67,29 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/GT.ppm)
)
endif()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/GT.no_shadows.ppm)
add_custom_command(TARGET rendering_integration_nahida_preview_scene POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_CURRENT_SOURCE_DIR}/GT.no_shadows.ppm
$<TARGET_FILE_DIR:rendering_integration_nahida_preview_scene>/GT.no_shadows.ppm
)
endif()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/GT.forward_lit.ppm)
add_custom_command(TARGET rendering_integration_nahida_preview_scene POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_CURRENT_SOURCE_DIR}/GT.forward_lit.ppm
$<TARGET_FILE_DIR:rendering_integration_nahida_preview_scene>/GT.forward_lit.ppm
)
endif()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/GT.unlit.ppm)
add_custom_command(TARGET rendering_integration_nahida_preview_scene POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_CURRENT_SOURCE_DIR}/GT.unlit.ppm
$<TARGET_FILE_DIR:rendering_integration_nahida_preview_scene>/GT.unlit.ppm
)
endif()
include(GoogleTest)
gtest_discover_tests(rendering_integration_nahida_preview_scene)

View File

@@ -86,6 +86,16 @@ const char* GetDiagnosticModeName(DiagnosticMode mode) {
}
}
const char* GetGoldenFileName(DiagnosticMode mode) {
switch (mode) {
case DiagnosticMode::Original: return "GT.ppm";
case DiagnosticMode::NoShadows: return "GT.no_shadows.ppm";
case DiagnosticMode::ForwardLit: return "GT.forward_lit.ppm";
case DiagnosticMode::Unlit: return "GT.unlit.ppm";
default: return "GT.ppm";
}
}
std::unordered_set<std::string> GetIsolationObjectNames() {
std::unordered_set<std::string> result;
const char* value = std::getenv("XC_NAHIDA_DIAG_ONLY");
@@ -713,6 +723,8 @@ TEST_P(NahidaPreviewSceneTest, RenderNahidaPreviewScene) {
RHISwapChain* swapChain = GetSwapChain();
ASSERT_NE(commandQueue, nullptr);
ASSERT_NE(swapChain, nullptr);
const DiagnosticMode diagnosticMode = GetDiagnosticMode();
const char* goldenFileName = GetGoldenFileName(diagnosticMode);
for (int frameIndex = 0; frameIndex <= kWarmupFrames; ++frameIndex) {
if (frameIndex > 0) {
@@ -730,12 +742,12 @@ TEST_P(NahidaPreviewSceneTest, RenderNahidaPreviewScene) {
ASSERT_EQ(image.width, kFrameWidth);
ASSERT_EQ(image.height, kFrameHeight);
const std::filesystem::path gtPath = ResolveRuntimePath("GT.ppm");
const std::filesystem::path gtPath = ResolveRuntimePath(goldenFileName);
if (!std::filesystem::exists(gtPath)) {
GTEST_SKIP() << "GT.ppm missing, screenshot captured for manual review: " << kD3D12Screenshot;
GTEST_SKIP() << goldenFileName << " missing, screenshot captured for manual review: " << kD3D12Screenshot;
}
ASSERT_TRUE(CompareWithGoldenTemplate(kD3D12Screenshot, "GT.ppm", 10.0f));
ASSERT_TRUE(CompareWithGoldenTemplate(kD3D12Screenshot, goldenFileName, 10.0f));
break;
}

View File

@@ -364,6 +364,7 @@ void PostProcessSceneTest::RenderFrame() {
request.surface = finalSurface;
request.postProcess.sourceSurface = mainSceneSurface;
request.postProcess.sourceColorView = mSceneColorShaderView;
request.postProcess.sourceColorState = ResourceStates::PixelShaderResource;
request.postProcess.destinationSurface = finalSurface;
request.postProcess.passes = &mPostProcessPasses;