From 2e961295bfa1bf16244c31d8398f0152716681a9 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Wed, 8 Apr 2026 02:53:12 +0800 Subject: [PATCH] Fix backpack material artifact rebuild --- .../XCEngine/Core/Asset/AssetDatabase.h | 2 +- .../src/Resources/Material/MaterialLoader.cpp | 22 ++++++- project/Assets/New Material.mat | 8 ++- .../Material/test_material_loader.cpp | 59 +++++++++++++++++++ 4 files changed, 88 insertions(+), 3 deletions(-) diff --git a/engine/include/XCEngine/Core/Asset/AssetDatabase.h b/engine/include/XCEngine/Core/Asset/AssetDatabase.h index 513259eb..4cadb4f4 100644 --- a/engine/include/XCEngine/Core/Asset/AssetDatabase.h +++ b/engine/include/XCEngine/Core/Asset/AssetDatabase.h @@ -99,7 +99,7 @@ public: const Containers::String& GetLastErrorMessage() const { return m_lastErrorMessage; } private: - static constexpr Core::uint32 kCurrentImporterVersion = 5; + static constexpr Core::uint32 kCurrentImporterVersion = 6; void EnsureProjectLayout(); void LoadSourceAssetDB(); diff --git a/engine/src/Resources/Material/MaterialLoader.cpp b/engine/src/Resources/Material/MaterialLoader.cpp index 423ab1f0..70251942 100644 --- a/engine/src/Resources/Material/MaterialLoader.cpp +++ b/engine/src/Resources/Material/MaterialLoader.cpp @@ -74,6 +74,16 @@ bool IsProjectRelativePath(const std::filesystem::path& path) { generic.rfind("../", 0) != 0; } +bool IsExplicitProjectRelativeDependencyPath(const std::filesystem::path& path) { + const std::string generic = path.lexically_normal().generic_string(); + return generic == "Assets" || + generic.rfind("Assets/", 0) == 0 || + generic == "Library" || + generic.rfind("Library/", 0) == 0 || + generic == "Packages" || + generic.rfind("Packages/", 0) == 0; +} + Containers::String ToProjectRelativeIfPossible(const std::filesystem::path& path) { const Containers::String& resourceRoot = ResourceManager::Get().GetResourceRoot(); const std::filesystem::path normalizedPath = path.lexically_normal(); @@ -96,16 +106,26 @@ Containers::String ResolveSourceDependencyPath(const Containers::String& depende } std::filesystem::path dependencyFsPath(dependencyPath.CStr()); + dependencyFsPath = dependencyFsPath.lexically_normal(); if (dependencyFsPath.is_absolute()) { return NormalizePathString(dependencyFsPath); } + const Containers::String& resourceRoot = ResourceManager::Get().GetResourceRoot(); + if (!resourceRoot.Empty()) { + const std::filesystem::path projectRoot(resourceRoot.CStr()); + const std::filesystem::path projectRelativeCandidate = projectRoot / dependencyFsPath; + if (IsExplicitProjectRelativeDependencyPath(dependencyFsPath) || + std::filesystem::exists(projectRelativeCandidate)) { + return ToProjectRelativeIfPossible(projectRelativeCandidate); + } + } + const std::filesystem::path sourceFsPath(sourcePath.CStr()); if (sourceFsPath.is_absolute()) { return ToProjectRelativeIfPossible(sourceFsPath.parent_path() / dependencyFsPath); } - const Containers::String& resourceRoot = ResourceManager::Get().GetResourceRoot(); if (!resourceRoot.Empty()) { return ToProjectRelativeIfPossible( std::filesystem::path(resourceRoot.CStr()) / diff --git a/project/Assets/New Material.mat b/project/Assets/New Material.mat index 8bff5729..c7c79595 100644 --- a/project/Assets/New Material.mat +++ b/project/Assets/New Material.mat @@ -1,4 +1,10 @@ { "shader": "builtin://shaders/unlit", - "renderQueue": "geometry" + "renderQueue": "geometry", + "properties": { + "_BaseColor": [1, 1, 1, 1] + }, + "textures": { + "_MainTex": "Assets/Models/backpack/diffuse.jpg" + } } diff --git a/tests/Resources/Material/test_material_loader.cpp b/tests/Resources/Material/test_material_loader.cpp index 7b2951d3..3d6e95ee 100644 --- a/tests/Resources/Material/test_material_loader.cpp +++ b/tests/Resources/Material/test_material_loader.cpp @@ -952,6 +952,65 @@ TEST(MaterialLoader, ResourceManagerLoadsProjectMaterialTextureAsLazyDependency) fs::remove_all(projectRoot); } +TEST(MaterialLoader, ResourceManagerPreservesProjectRelativeTexturePathWithoutDuplicatingAssetsPrefix) { + namespace fs = std::filesystem; + + ResourceManager& manager = ResourceManager::Get(); + manager.Initialize(); + + const fs::path projectRoot = fs::temp_directory_path() / "xc_material_project_relative_texture_path_test"; + const fs::path assetsDir = projectRoot / "Assets"; + const fs::path materialPath = assetsDir / "textured.material"; + const fs::path textureDir = assetsDir / "Models" / "backpack"; + const fs::path texturePath = textureDir / "checker.bmp"; + + fs::remove_all(projectRoot); + fs::create_directories(textureDir); + fs::copy_file( + GetMeshFixturePath("checker.bmp"), + texturePath, + fs::copy_options::overwrite_existing); + + { + std::ofstream materialFile(materialPath); + ASSERT_TRUE(materialFile.is_open()); + materialFile << "{\n"; + materialFile << " \"renderQueue\": \"geometry\",\n"; + materialFile << " \"textures\": {\n"; + materialFile << " \"baseColorTexture\": \"Assets/Models/backpack/checker.bmp\"\n"; + materialFile << " }\n"; + materialFile << "}\n"; + } + + manager.SetResourceRoot(projectRoot.string().c_str()); + + const auto materialHandle = manager.Load("Assets/textured.material"); + ASSERT_TRUE(materialHandle.IsValid()); + ASSERT_EQ(materialHandle->GetTextureBindingCount(), 1u); + EXPECT_EQ(materialHandle->GetTextureBindingName(0), "baseColorTexture"); + EXPECT_TRUE(materialHandle->GetTextureBindingAssetRef(0).IsValid()); + EXPECT_EQ( + fs::path(materialHandle->GetTextureBindingPath(0).CStr()).lexically_normal().generic_string(), + texturePath.lexically_normal().generic_string()); + EXPECT_EQ( + fs::path(materialHandle->GetTextureBindingPath(0).CStr()).lexically_normal().generic_string().find("Assets/Assets"), + std::string::npos); + + const ResourceHandle initialTexture = materialHandle->GetTexture("baseColorTexture"); + EXPECT_FALSE(initialTexture.IsValid()); + EXPECT_GT(manager.GetAsyncPendingCount(), 0u); + + ASSERT_TRUE(PumpAsyncLoadsUntilIdle(manager)); + const ResourceHandle loadedTexture = materialHandle->GetTexture("baseColorTexture"); + ASSERT_TRUE(loadedTexture.IsValid()); + EXPECT_EQ(loadedTexture->GetWidth(), 2u); + EXPECT_EQ(loadedTexture->GetHeight(), 2u); + + manager.SetResourceRoot(""); + manager.Shutdown(); + fs::remove_all(projectRoot); +} + TEST(MaterialLoader, AssetDatabaseReimportsMaterialWhenTextureDependencyChanges) { namespace fs = std::filesystem; using namespace std::chrono_literals;