Hello,
We’ve identified a crash when assembling a metahuman character when the project uses asset virtualization.
Do note that our game content is virtualized while the engine content is not.
The crash occurs in the FMetaHumanCharacterEditorBuild::DuplicateDepedenciesToNewRoot function. The source asset is first serialized into a FDuplicateDataWriter with BulkData, when the target asset is read back in the FDuplicateDataReader, the serialization code reads from the target package that the bulk data is Virtualized and skips the BulkData reads. This causes a serialisation mismatch and results in a crash.
We worked around this issue by rehydrating all the content in the new root folder “/Game/MetaHumans/Common” before running the assembly but this is messy and would have to be done almost every time we want to run Assembly.
I’ll see if virtualizing the engine content helps and update this ticket accordingly. (edit: resaving and submitting the engine content from the editor did not virtualize those assets as expected)
Incidentally, while the workaround does get us through the assembly process, the editor does crash shortly after in the render thread due to a dangling pointer in one of the FMaterialInstanceResource structs. I’ll investigate this further and will update this ticket and possibly open a new one if the issue turns out to be unrelated.
Many Thanks,
Benjamin
[Attachment Removed]
Steps to Reproduce
- Create a project with support for asset virtualization and with some metahuman characters in it.
- The assets in /Game/MetaHuman/Common should be virtualized. The assets in the MetaHumanContent engine plugin are not.
- Open a metahuman character asset and run “Assemble” on it. Notice the crash.
We did manage to generate a faster repro by running the following code (invoked from a console command for easy repro)
FString FromAssetPath = TEXT("/MetaHumanCharacter/Optional/BodyTextures/T_Skin_Microtiling_M.T_Skin_Microtiling_M");
FString ToAssetPackageName = TEXT("/Game/MetaHumans/Common/Optional/BodyTextures/T_Skin_Microtiling_M");
UObject* DependencyAsset = LoadObject<UObject>(nullptr, FromAssetPath);
UPackage* TargetPackage = UPackageTools::FindOrCreatePackageForAssetType(FName{ ToAssetPackageName }, DependencyAsset->GetClass());
const FString AssetName = DependencyAsset->GetName();
UObject* DuplicatedDependency = DuplicateObject(DependencyAsset, TargetPackage, *AssetName);
This simply requires that “/Game/MetaHumans/Common/Optional/BodyTextures/T_Skin_Microtiling_M” be virtualized.
[Attachment Removed]
Hi Benjamin.
I spoke to the engineering team about this yesterday.
The /Game/MetaHumans/Common assets folder is a ‘feature’ of MetaHuman assembly that uses a custom method to overwrite assets that is not otherwise exposed in the editor. Unfortunately, it has not been fully verified as being compatible with a project that uses virtualized assets. We do consider this use case to be something we support, and so we log some work to look at this further as part of future development in this area.
This does however mean that the safest workaround would be exclude the Common folder from the virtualized content, as you are already doing with engine content.
Thanks,
Mark.
[Attachment Removed]
Repro steps update:
It is possible to repro without implicating Metahuman assets at all, you can simply create 2 identical texture assets T_A and T_B in the game project.
Duplicating T_A into the T_B package (using the code provided above) will crash if the destination package T_B is virtualized but the source package T_A is not.
If both or neither packages are virtualized, the duplication seems to run just fine.
[Attachment Removed]
Hello Mark,
Thanks for your reply, we did end up taking your advice and Excluding the Metahumans/Common folder from virtualization like so
; DefaultEngine.ini
[/Script/Virtualization.VirtualizationFilterSettings]
+ExcludePackagePaths="/Game/MetaHumans/Common/"
You did mention
> … MetaHuman assembly that uses a custom method to overwrite assets that is not otherwise exposed in the editor.
However the simpler repro I provided causes a crash using only the DuplicateObject function which is part of CoreUObject and very much exposed to the rest of the engine. I don’t think Metahuman is necessarily doing anything wrong here but the low level functions of the engine do not safely support duplicating objects between virtualized and non virtualized packages.
By the way, I did mention an other crash happening later in the render thread after running Assembly. [Here is the UDN ticket for it for [Content removed]
[Attachment Removed]
You’re right that your repro uses only core engine code, but we were recently advised by the core team that overwriting existing UObjects like this is prone to bugs and should be avoided. Unfortunately it’s one of those cases where the engine won’t prevent you from doing something that’s not well supported.
In the long term we’re planning to move away from duplicating common assets into the project to avoid issues like this.
Thanks for the other ticket. We’re looking into it.
[Attachment Removed]