Add Nahida model import and preview pipeline

This commit is contained in:
2026-04-11 20:16:49 +08:00
parent 8f71f99de4
commit 030230eb1f
87 changed files with 7245 additions and 117 deletions

View File

@@ -1,6 +1,7 @@
#include <gtest/gtest.h>
#include <XCEngine/Core/Asset/AssetDatabase.h>
#include <XCEngine/Core/Asset/ArtifactContainer.h>
#include <XCEngine/Core/Asset/ResourceManager.h>
#include <XCEngine/Resources/Mesh/Mesh.h>
#include <XCEngine/Resources/Mesh/MeshLoader.h>
@@ -85,11 +86,24 @@ TEST(ModelImportPipeline, AssetDatabaseImportsObjAsModelArtifact) {
AssetDatabase::ResolvedAsset resolvedAsset;
ASSERT_TRUE(database.EnsureArtifact("Assets/textured_triangle.obj", ResourceType::Model, resolvedAsset));
ASSERT_TRUE(resolvedAsset.artifactReady);
EXPECT_EQ(fs::path(resolvedAsset.artifactMainPath.CStr()).filename().string(), "main.xcmodel");
EXPECT_EQ(fs::path(resolvedAsset.artifactMainPath.CStr()).extension().string(), ".xcmodel");
EXPECT_TRUE(fs::exists(resolvedAsset.artifactMainPath.CStr()));
EXPECT_TRUE(fs::exists(fs::path(resolvedAsset.artifactDirectory.CStr()) / "mesh_0.xcmesh"));
EXPECT_TRUE(fs::exists(fs::path(resolvedAsset.artifactDirectory.CStr()) / "material_0.xcmat"));
EXPECT_TRUE(fs::exists(fs::path(resolvedAsset.artifactDirectory.CStr()) / "texture_0.xctex"));
XCEngine::Containers::Array<XCEngine::Core::uint8> payload;
EXPECT_TRUE(ReadArtifactContainerEntryPayload(
resolvedAsset.artifactMainPath,
"mesh_0.xcmesh",
ResourceType::Mesh,
payload));
EXPECT_TRUE(ReadArtifactContainerEntryPayload(
resolvedAsset.artifactMainPath,
"material_0.xcmat",
ResourceType::Material,
payload));
EXPECT_TRUE(ReadArtifactContainerEntryPayload(
resolvedAsset.artifactMainPath,
"texture_0.xctex",
ResourceType::Texture,
payload));
ModelLoader modelLoader;
const LoadResult modelResult = modelLoader.Load(resolvedAsset.artifactMainPath);
@@ -109,7 +123,8 @@ TEST(ModelImportPipeline, AssetDatabaseImportsObjAsModelArtifact) {
MeshLoader meshLoader;
const LoadResult meshResult =
meshLoader.Load((fs::path(resolvedAsset.artifactDirectory.CStr()) / "mesh_0.xcmesh").string().c_str());
meshLoader.Load(
BuildArtifactContainerEntryPath(resolvedAsset.artifactMainPath, "mesh_0.xcmesh"));
ASSERT_TRUE(meshResult);
ASSERT_NE(meshResult.resource, nullptr);
@@ -182,4 +197,64 @@ TEST(ModelImportPipeline, ResourceManagerLoadsModelFromProjectAsset) {
fs::remove_all(projectRoot);
}
TEST(ModelImportPipeline, ProjectNahidaSampleArtifactPreservesFallbackUv1Semantic) {
namespace fs = std::filesystem;
const fs::path repositoryRoot = GetRepositoryRoot();
const fs::path projectRoot = repositoryRoot / "project";
const fs::path nahidaModelPath =
projectRoot / "Assets" / "Characters" / "Nahida" / "Model" / "Avatar_Loli_Catalyst_Nahida.fbx";
const fs::path assimpDllPath = repositoryRoot / "engine" / "third_party" / "assimp" / "bin" / "assimp-vc143-mt.dll";
if (!fs::exists(nahidaModelPath)) {
GTEST_SKIP() << "Nahida sample model is not available in the local project fixture.";
}
ASSERT_TRUE(fs::exists(assimpDllPath));
#ifdef _WIN32
AssimpDllGuard dllGuard;
dllGuard.module = LoadLibraryW(assimpDllPath.wstring().c_str());
ASSERT_NE(dllGuard.module, nullptr);
#endif
ResourceManager& manager = ResourceManager::Get();
manager.Initialize();
manager.SetResourceRoot(projectRoot.string().c_str());
AssetDatabase database;
database.Initialize(projectRoot.string().c_str());
AssetDatabase::ResolvedAsset resolvedAsset;
ASSERT_TRUE(database.EnsureArtifact(
"Assets/Characters/Nahida/Model/Avatar_Loli_Catalyst_Nahida.fbx",
ResourceType::Model,
resolvedAsset));
ASSERT_TRUE(resolvedAsset.artifactReady);
EXPECT_EQ(fs::path(resolvedAsset.artifactMainPath.CStr()).extension().string(), ".xcmodel");
MeshLoader meshLoader;
const LoadResult meshResult =
meshLoader.Load(BuildArtifactContainerEntryPath(resolvedAsset.artifactMainPath, "mesh_0.xcmesh"));
ASSERT_TRUE(meshResult);
ASSERT_NE(meshResult.resource, nullptr);
auto* mesh = static_cast<Mesh*>(meshResult.resource);
ASSERT_NE(mesh, nullptr);
EXPECT_TRUE(HasVertexAttribute(mesh->GetVertexAttributes(), VertexAttribute::UV0));
EXPECT_TRUE(HasVertexAttribute(mesh->GetVertexAttributes(), VertexAttribute::UV1));
EXPECT_TRUE(HasVertexAttribute(mesh->GetVertexAttributes(), VertexAttribute::Color));
const auto* vertices = static_cast<const StaticMeshVertex*>(mesh->GetVertexData());
ASSERT_NE(vertices, nullptr);
ASSERT_GT(mesh->GetVertexCount(), 0u);
EXPECT_FLOAT_EQ(vertices[0].uv0.x, vertices[0].uv1.x);
EXPECT_FLOAT_EQ(vertices[0].uv0.y, vertices[0].uv1.y);
delete mesh;
database.Shutdown();
manager.SetResourceRoot("");
manager.Shutdown();
}
} // namespace