Formalize GaussianSplat scene extraction
This commit is contained in:
182
tests/Components/test_gaussian_splat_renderer_component.cpp
Normal file
182
tests/Components/test_gaussian_splat_renderer_component.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <XCEngine/Components/GaussianSplatRendererComponent.h>
|
||||
#include <XCEngine/Components/GameObject.h>
|
||||
#include <XCEngine/Core/Asset/IResource.h>
|
||||
#include <XCEngine/Core/Asset/ResourceManager.h>
|
||||
#include <XCEngine/Core/IO/IResourceLoader.h>
|
||||
#include <XCEngine/Resources/GaussianSplat/GaussianSplat.h>
|
||||
#include <XCEngine/Resources/Material/Material.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
using namespace XCEngine::Components;
|
||||
using namespace XCEngine::Resources;
|
||||
|
||||
namespace {
|
||||
|
||||
GaussianSplat* CreateTestGaussianSplat(const char* name, const char* path) {
|
||||
auto* gaussianSplat = new GaussianSplat();
|
||||
IResource::ConstructParams params = {};
|
||||
params.name = name;
|
||||
params.path = path;
|
||||
params.guid = ResourceGUID::Generate(path);
|
||||
gaussianSplat->Initialize(params);
|
||||
|
||||
GaussianSplatMetadata metadata = {};
|
||||
metadata.splatCount = 1u;
|
||||
|
||||
XCEngine::Containers::Array<GaussianSplatSection> sections;
|
||||
sections.Resize(1);
|
||||
sections[0].type = GaussianSplatSectionType::Positions;
|
||||
sections[0].format = GaussianSplatSectionFormat::VectorFloat32;
|
||||
sections[0].dataOffset = 0u;
|
||||
sections[0].dataSize = sizeof(GaussianSplatPositionRecord);
|
||||
sections[0].elementCount = 1u;
|
||||
sections[0].elementStride = sizeof(GaussianSplatPositionRecord);
|
||||
|
||||
XCEngine::Containers::Array<XCEngine::Core::uint8> payload;
|
||||
payload.Resize(sizeof(GaussianSplatPositionRecord));
|
||||
const GaussianSplatPositionRecord positionRecord = { XCEngine::Math::Vector3(1.0f, 2.0f, 3.0f) };
|
||||
std::memcpy(payload.Data(), &positionRecord, sizeof(positionRecord));
|
||||
|
||||
EXPECT_TRUE(gaussianSplat->CreateOwned(metadata, std::move(sections), std::move(payload)));
|
||||
return gaussianSplat;
|
||||
}
|
||||
|
||||
Material* CreateTestMaterial(const char* name, const char* path) {
|
||||
auto* material = new Material();
|
||||
IResource::ConstructParams params = {};
|
||||
params.name = name;
|
||||
params.path = path;
|
||||
params.guid = ResourceGUID::Generate(path);
|
||||
material->Initialize(params);
|
||||
return material;
|
||||
}
|
||||
|
||||
class FakeAsyncGaussianSplatLoader final : public IResourceLoader {
|
||||
public:
|
||||
ResourceType GetResourceType() const override { return ResourceType::GaussianSplat; }
|
||||
|
||||
XCEngine::Containers::Array<XCEngine::Containers::String> GetSupportedExtensions() const override {
|
||||
XCEngine::Containers::Array<XCEngine::Containers::String> extensions;
|
||||
extensions.PushBack("ply");
|
||||
extensions.PushBack("xcgsplat");
|
||||
return extensions;
|
||||
}
|
||||
|
||||
bool CanLoad(const XCEngine::Containers::String& path) const override {
|
||||
(void)path;
|
||||
return true;
|
||||
}
|
||||
|
||||
LoadResult Load(
|
||||
const XCEngine::Containers::String& path,
|
||||
const ImportSettings* settings = nullptr) override {
|
||||
(void)settings;
|
||||
return LoadResult(CreateTestGaussianSplat("AsyncGaussianSplat", path.CStr()));
|
||||
}
|
||||
|
||||
ImportSettings* GetDefaultSettings() const override {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
bool PumpAsyncLoadsUntilIdle(
|
||||
ResourceManager& manager,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds(2000)) {
|
||||
const auto deadline = std::chrono::steady_clock::now() + timeout;
|
||||
while (manager.IsAsyncLoading() && std::chrono::steady_clock::now() < deadline) {
|
||||
manager.UpdateAsyncLoads();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
}
|
||||
|
||||
manager.UpdateAsyncLoads();
|
||||
return !manager.IsAsyncLoading();
|
||||
}
|
||||
|
||||
TEST(GaussianSplatRendererComponent_Test, SetResourcesCachesHandlesPathsAndFlags) {
|
||||
GameObject gameObject("GaussianSplatHolder");
|
||||
auto* component = gameObject.AddComponent<GaussianSplatRendererComponent>();
|
||||
GaussianSplat* gaussianSplat = CreateTestGaussianSplat("Room", "GaussianSplats/room.xcgsplat");
|
||||
Material* material = CreateTestMaterial("GaussianSplatMaterial", "Materials/gaussian_splat.mat");
|
||||
|
||||
component->SetGaussianSplat(gaussianSplat);
|
||||
component->SetMaterial(material);
|
||||
component->SetCastShadows(false);
|
||||
component->SetReceiveShadows(false);
|
||||
|
||||
EXPECT_EQ(component->GetGaussianSplat(), gaussianSplat);
|
||||
EXPECT_EQ(component->GetGaussianSplatPath(), "GaussianSplats/room.xcgsplat");
|
||||
EXPECT_EQ(component->GetMaterial(), material);
|
||||
EXPECT_EQ(component->GetMaterialPath(), "Materials/gaussian_splat.mat");
|
||||
EXPECT_FALSE(component->GetCastShadows());
|
||||
EXPECT_FALSE(component->GetReceiveShadows());
|
||||
|
||||
component->ClearGaussianSplat();
|
||||
component->ClearMaterial();
|
||||
delete gaussianSplat;
|
||||
delete material;
|
||||
}
|
||||
|
||||
TEST(GaussianSplatRendererComponent_Test, SerializeAndDeserializePreservesVirtualPathsAndFlags) {
|
||||
GaussianSplatRendererComponent source;
|
||||
source.SetGaussianSplatPath("test://gaussian_splats/room.ply");
|
||||
source.SetMaterialPath("test://materials/gaussian_splat.mat");
|
||||
source.SetCastShadows(false);
|
||||
source.SetReceiveShadows(true);
|
||||
|
||||
std::stringstream stream;
|
||||
source.Serialize(stream);
|
||||
const std::string serialized = stream.str();
|
||||
EXPECT_NE(serialized.find("gaussianSplatPath=test://gaussian_splats/room.ply;"), std::string::npos);
|
||||
EXPECT_NE(serialized.find("materialPath=test://materials/gaussian_splat.mat;"), std::string::npos);
|
||||
EXPECT_NE(serialized.find("castShadows=0;"), std::string::npos);
|
||||
EXPECT_NE(serialized.find("receiveShadows=1;"), std::string::npos);
|
||||
|
||||
GaussianSplatRendererComponent target;
|
||||
std::stringstream deserializeStream(serialized);
|
||||
target.Deserialize(deserializeStream);
|
||||
|
||||
EXPECT_EQ(target.GetGaussianSplatPath(), "test://gaussian_splats/room.ply");
|
||||
EXPECT_EQ(target.GetMaterialPath(), "test://materials/gaussian_splat.mat");
|
||||
EXPECT_FALSE(target.GetCastShadows());
|
||||
EXPECT_TRUE(target.GetReceiveShadows());
|
||||
EXPECT_FALSE(target.GetGaussianSplatAssetRef().IsValid());
|
||||
EXPECT_FALSE(target.GetMaterialAssetRef().IsValid());
|
||||
}
|
||||
|
||||
TEST(GaussianSplatRendererComponent_Test, DeferredSceneDeserializeLoadsGaussianSplatAsyncByPath) {
|
||||
ResourceManager& manager = ResourceManager::Get();
|
||||
manager.Initialize();
|
||||
|
||||
IResourceLoader* originalLoader = manager.GetLoader(ResourceType::GaussianSplat);
|
||||
FakeAsyncGaussianSplatLoader fakeLoader;
|
||||
manager.RegisterLoader(&fakeLoader);
|
||||
|
||||
GaussianSplatRendererComponent target;
|
||||
const auto pendingBeforeDeserialize = manager.GetAsyncPendingCount();
|
||||
{
|
||||
ResourceManager::ScopedDeferredSceneLoad deferredLoadScope;
|
||||
EXPECT_TRUE(manager.IsDeferredSceneLoadEnabled());
|
||||
std::stringstream stream(
|
||||
"gaussianSplatPath=test://gaussian_splats/async_room.ply;gaussianSplatRef=;materialRef=;castShadows=1;receiveShadows=1;");
|
||||
target.Deserialize(stream);
|
||||
}
|
||||
|
||||
EXPECT_EQ(target.GetGaussianSplatPath(), "test://gaussian_splats/async_room.ply");
|
||||
EXPECT_EQ(target.GetGaussianSplat(), nullptr);
|
||||
EXPECT_GT(manager.GetAsyncPendingCount(), pendingBeforeDeserialize);
|
||||
ASSERT_TRUE(PumpAsyncLoadsUntilIdle(manager));
|
||||
ASSERT_NE(target.GetGaussianSplat(), nullptr);
|
||||
EXPECT_EQ(target.GetGaussianSplatPath(), "test://gaussian_splats/async_room.ply");
|
||||
EXPECT_EQ(target.GetGaussianSplat()->GetSplatCount(), 1u);
|
||||
|
||||
manager.RegisterLoader(originalLoader);
|
||||
manager.Shutdown();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user