Add Nahida model import and preview pipeline
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#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/BuiltinResources.h>
|
||||
#include <XCEngine/Resources/Material/MaterialLoader.h>
|
||||
@@ -304,13 +305,19 @@ TEST(MeshLoader, ProjectBackpackSampleArtifactRetainsSectionMaterialTextures) {
|
||||
AssetDatabase::ResolvedAsset resolvedAsset;
|
||||
ASSERT_TRUE(database.EnsureArtifact("Assets/Models/backpack/backpack.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");
|
||||
|
||||
const fs::path meshArtifactPath = fs::path(resolvedAsset.artifactDirectory.CStr()) / "mesh_0.xcmesh";
|
||||
ASSERT_TRUE(fs::exists(meshArtifactPath));
|
||||
const String meshArtifactPath =
|
||||
BuildArtifactContainerEntryPath(resolvedAsset.artifactMainPath, "mesh_0.xcmesh");
|
||||
XCEngine::Containers::Array<XCEngine::Core::uint8> payload;
|
||||
ASSERT_TRUE(ReadArtifactContainerEntryPayload(
|
||||
resolvedAsset.artifactMainPath,
|
||||
"mesh_0.xcmesh",
|
||||
ResourceType::Mesh,
|
||||
payload));
|
||||
|
||||
MeshLoader loader;
|
||||
const LoadResult result = loader.Load(meshArtifactPath.string().c_str());
|
||||
const LoadResult result = loader.Load(meshArtifactPath);
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_NE(result.resource, nullptr);
|
||||
|
||||
@@ -331,6 +338,60 @@ TEST(MeshLoader, ProjectBackpackSampleArtifactRetainsSectionMaterialTextures) {
|
||||
manager.Shutdown();
|
||||
}
|
||||
|
||||
TEST(MeshLoader, ProjectNahidaSampleMarksFallbackUv1WhenSecondaryChannelIsAbsent) {
|
||||
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
|
||||
struct DllGuard {
|
||||
HMODULE module = nullptr;
|
||||
~DllGuard() {
|
||||
if (module != nullptr) {
|
||||
FreeLibrary(module);
|
||||
}
|
||||
}
|
||||
} 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());
|
||||
|
||||
MeshLoader loader;
|
||||
const LoadResult result = loader.Load(nahidaModelPath.string().c_str());
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_NE(result.resource, nullptr);
|
||||
|
||||
auto* mesh = static_cast<Mesh*>(result.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;
|
||||
manager.SetResourceRoot("");
|
||||
manager.Shutdown();
|
||||
}
|
||||
|
||||
TEST(MeshLoader, AssetDatabaseCreatesModelArtifactAndReusesItWithoutReimport) {
|
||||
namespace fs = std::filesystem;
|
||||
using namespace std::chrono_literals;
|
||||
@@ -378,22 +439,35 @@ TEST(MeshLoader, AssetDatabaseCreatesModelArtifactAndReusesItWithoutReimport) {
|
||||
ASSERT_TRUE(database.EnsureArtifact("Assets/textured_triangle.obj", ResourceType::Model, firstResolve));
|
||||
ASSERT_TRUE(firstResolve.exists);
|
||||
ASSERT_TRUE(firstResolve.artifactReady);
|
||||
EXPECT_EQ(fs::path(firstResolve.artifactMainPath.CStr()).filename().string(), "main.xcmodel");
|
||||
EXPECT_EQ(fs::path(firstResolve.artifactMainPath.CStr()).extension().string(), ".xcmodel");
|
||||
EXPECT_TRUE(fs::exists(projectRoot / "Assets" / "textured_triangle.obj.meta"));
|
||||
EXPECT_TRUE(fs::exists(projectRoot / "Library" / "SourceAssetDB" / "assets.db"));
|
||||
EXPECT_TRUE(fs::exists(projectRoot / "Library" / "ArtifactDB" / "artifacts.db"));
|
||||
EXPECT_TRUE(fs::exists(projectRoot / "Library" / "assets.db"));
|
||||
EXPECT_TRUE(fs::exists(projectRoot / "Library" / "artifacts.db"));
|
||||
EXPECT_TRUE(fs::exists(firstResolve.artifactMainPath.CStr()));
|
||||
EXPECT_TRUE(fs::exists(fs::path(firstResolve.artifactDirectory.CStr()) / "mesh_0.xcmesh"));
|
||||
EXPECT_TRUE(fs::exists(
|
||||
fs::path(firstResolve.artifactDirectory.CStr()) /
|
||||
("material_" + std::to_string(sourceMaterialIndex) + ".xcmat")));
|
||||
EXPECT_TRUE(fs::exists((fs::path(firstResolve.artifactDirectory.CStr()) / "texture_0.xctex")));
|
||||
const String meshArtifactPath =
|
||||
BuildArtifactContainerEntryPath(firstResolve.artifactMainPath, "mesh_0.xcmesh");
|
||||
const String materialArtifactPath = BuildArtifactContainerEntryPath(
|
||||
firstResolve.artifactMainPath,
|
||||
String(("material_" + std::to_string(sourceMaterialIndex) + ".xcmat").c_str()));
|
||||
XCEngine::Containers::Array<XCEngine::Core::uint8> artifactPayload;
|
||||
EXPECT_TRUE(ReadArtifactContainerEntryPayload(
|
||||
firstResolve.artifactMainPath,
|
||||
"mesh_0.xcmesh",
|
||||
ResourceType::Mesh,
|
||||
artifactPayload));
|
||||
EXPECT_TRUE(ReadArtifactContainerEntryPayload(
|
||||
firstResolve.artifactMainPath,
|
||||
String(("material_" + std::to_string(sourceMaterialIndex) + ".xcmat").c_str()),
|
||||
ResourceType::Material,
|
||||
artifactPayload));
|
||||
EXPECT_TRUE(ReadArtifactContainerEntryPayload(
|
||||
firstResolve.artifactMainPath,
|
||||
"texture_0.xctex",
|
||||
ResourceType::Texture,
|
||||
artifactPayload));
|
||||
|
||||
MaterialLoader materialLoader;
|
||||
LoadResult materialArtifactResult =
|
||||
materialLoader.Load(
|
||||
(fs::path(firstResolve.artifactDirectory.CStr()) /
|
||||
("material_" + std::to_string(sourceMaterialIndex) + ".xcmat")).string().c_str());
|
||||
LoadResult materialArtifactResult = materialLoader.Load(materialArtifactPath);
|
||||
ASSERT_TRUE(materialArtifactResult);
|
||||
ASSERT_NE(materialArtifactResult.resource, nullptr);
|
||||
auto* artifactMaterial = static_cast<Material*>(materialArtifactResult.resource);
|
||||
@@ -414,8 +488,7 @@ TEST(MeshLoader, AssetDatabaseCreatesModelArtifactAndReusesItWithoutReimport) {
|
||||
delete artifactMaterial;
|
||||
|
||||
MeshLoader meshLoader;
|
||||
LoadResult meshArtifactResult =
|
||||
meshLoader.Load((fs::path(firstResolve.artifactDirectory.CStr()) / "mesh_0.xcmesh").string().c_str());
|
||||
LoadResult meshArtifactResult = meshLoader.Load(meshArtifactPath);
|
||||
ASSERT_TRUE(meshArtifactResult);
|
||||
ASSERT_NE(meshArtifactResult.resource, nullptr);
|
||||
auto* artifactMesh = static_cast<Mesh*>(meshArtifactResult.resource);
|
||||
@@ -566,7 +639,13 @@ TEST(MeshLoader, ResourceManagerLoadsImportedMeshSubAssetByAssetRefFromProjectAs
|
||||
ASSERT_TRUE(meshAssetRef.IsValid());
|
||||
|
||||
ASSERT_TRUE(manager.TryResolveAssetPath(meshAssetRef, resolvedMeshPath));
|
||||
EXPECT_EQ(fs::path(resolvedMeshPath.CStr()).filename().string(), "mesh_0.xcmesh");
|
||||
String resolvedContainerPath;
|
||||
String resolvedEntryName;
|
||||
ASSERT_TRUE(TryParseArtifactContainerEntryPath(
|
||||
resolvedMeshPath,
|
||||
resolvedContainerPath,
|
||||
resolvedEntryName));
|
||||
EXPECT_EQ(resolvedEntryName, "mesh_0.xcmesh");
|
||||
}
|
||||
|
||||
manager.UnloadAll();
|
||||
|
||||
Reference in New Issue
Block a user