Fix backpack material artifact rebuild

This commit is contained in:
2026-04-08 02:53:12 +08:00
parent 0a392e1311
commit 2e961295bf
4 changed files with 88 additions and 3 deletions

View File

@@ -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();

View File

@@ -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()) /

View File

@@ -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"
}
}

View File

@@ -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<Material>("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<Texture> initialTexture = materialHandle->GetTexture("baseColorTexture");
EXPECT_FALSE(initialTexture.IsValid());
EXPECT_GT(manager.GetAsyncPendingCount(), 0u);
ASSERT_TRUE(PumpAsyncLoadsUntilIdle(manager));
const ResourceHandle<Texture> 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;