UE4.27.2 纹理 Reimport With New File 的调试分析
2025-06-01 10:52:45

Reimport With New File 入口

FAssetFileContextMenu::ExecuteReimportWithNewFile 收集所有重新导入的资产,传给 FReimportManager::ValidateAllSourceFileAndReimport

FReimportManager::ValidateAllSourceFileAndReimport 处理那些丢失的资产对象 missing file,然后把剩下的那些资产对象传给 FReimportManager::ReimportMultiple

FReimportManager::ReimportMultiple 遍历资产对象,对每一个资产对象调用 FReimportManager::Reimport 进行重新导入

FReimportManager::Reimport 对这一个资产对象的所有源文件检查是否丢失等,然后寻找合适的 FReimportHandler,最终调用 FReimportHandler::Reimport 来重新导入

这是一个虚函数,以实现导入行为的多态

对于重新加载纹理,进入的是 UReimportTextureFactory::Reimport

最终到 UTextureFactory::FactoryCreateBinary,堆栈如下,就不分析了

1
2
3
4
5
6
7
8
9
10
UTextureFactory::FactoryCreateBinary(UClass *, UObject *, FName, EObjectFlags, UObject *, const wchar_t *, const unsigned char *&, const unsigned char *, FFeedbackContext *) EditorFactories.cpp:4337
UFactory::FactoryCreateBinary(UClass *, UObject *, FName, EObjectFlags, UObject *, const wchar_t *, const unsigned char *&, const unsigned char *, FFeedbackContext *, bool &) Factory.h:354
UFactory::FactoryCreateFile(UClass *, UObject *, FName, EObjectFlags, const FString &, const wchar_t *, FFeedbackContext *, bool &) Factory.cpp:112
UFactory::ImportObject(UClass *, UObject *, FName, EObjectFlags, const FString &, const wchar_t *, bool &) Factory.cpp:201
UReimportTextureFactory::Reimport(UObject *) EditorFactories.cpp:6018
FReimportHandler::Reimport(UObject *, int) EditorReimportHandler.h:238
FReimportManager::Reimport(UObject *, bool, bool, FString, FReimportHandler *, int, bool, bool) Editor.cpp:375
FReimportManager::ReimportMultiple(TArrayView<…>, bool, bool, FString, FReimportHandler *, int, bool, bool) Editor.cpp:622
FReimportManager::ValidateAllSourceFileAndReimport(TArray<…> &, bool, int, bool, bool) Editor.cpp:583
FAssetFileContextMenu::ExecuteReimportWithNewFile(int) AssetFileContextMenu.cpp:1444

UTextureFactory::FactoryCreateBinary

删掉了类型检查、事件、UDIM、保存图片导入设置、guid、法线贴图、LOD 组、恢复图片导入设置、纹理数组、自动创建纹理等内容,精简为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
UObject* UTextureFactory::FactoryCreateBinary
(
UClass* Class,
UObject* InParent,
FName Name,
EObjectFlags Flags,
UObject* Context,
const TCHAR* Type,
const uint8*& Buffer,
const uint8* BufferEnd,
FFeedbackContext* Warn
)
{
FName TextureName = Name;

// if the texture already exists, remember the user settings
UTexture* ExistingTexture = FindObject<UTexture>( InParent, *TextureName.ToString() );
UTexture2D* ExistingTexture2D = FindObject<UTexture2D>( InParent, *TextureName.ToString() );

if (ExistingTexture2D)
{
// Update with new settings, which should disable streaming...
ExistingTexture2D->UpdateResource();
}
if(ExistingTexture)
{
// Wait for InitRHI() to complete before the FTextureReferenceReplacer calls ReleaseRHI() to follow the workflow.
// Static texture needs to avoid having pending InitRHI() before enqueuing ReleaseRHI() to safely track access of the PlatformData on the renderthread.
ExistingTexture->WaitForPendingInitOrStreaming();
}

FTextureReferenceReplacer RefReplacer(ExistingTexture);

UTexture* Texture = nullptr;
Texture = ImportTexture(Class, InParent, TextureName, Flags, Type, Buffer, BufferEnd, Warn);
if (Texture)
{
Texture->AssetImportData->Update(CurrentFilename, FileHash.IsValid() ? &FileHash : nullptr);
}

if(!Texture)
{
if (ExistingTexture)
{
// We failed to import over the existing texture. Make sure the resource is ready in the existing texture.
ExistingTexture->UpdateResource();
}

return nullptr;
}

//Replace the reference for the new texture with the existing one so that all current users still have valid references.
RefReplacer.Replace(Texture);

return Texture;
}

前面是确保被替换的纹理已经初始化了 RHI 资源

然后就是替换的核心逻辑了 RefReplacer.Replace(Texture);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/** 
* Replaces the RHI reference of one texture with another.
* Allows one texture to be replaced with another at runtime and have all existing references to it remain valid.
*/
struct FTextureReferenceReplacer
{
FTextureReferenceRHIRef OriginalRef;

FTextureReferenceReplacer(UTexture* OriginalTexture)
{
if (OriginalTexture)
{
OriginalTexture->ReleaseResource();
OriginalRef = OriginalTexture->TextureReference.TextureReferenceRHI;
}
else
{
OriginalRef = nullptr;
}
}

void Replace(UTexture* NewTexture)
{
if (OriginalRef)
{
NewTexture->TextureReference.TextureReferenceRHI = OriginalRef;
}
}
};

搜索了整个引擎,只有 Editor 的这个 reimport 的功能使用了 FTextureReferenceReplacer 这个结构体