SaveGeneratedTexture2DAsset can crash for a variety of reasons when overwriting an existing texture asset. When no existing asset exists, the function simply moves the provided transient Texture asset to the specified non-transient package. However, in the case the asset already exists, the function tries to do a complex texture to texture copy from the source to destination asset. Unfortunately there are a number of edge cases which are not handled properly, causing a number of crash or corrupt texture output scenarios. Note that in order to save an existing non-transient texture using this function, the UTexture can be duplicated to a transient package with DuplicateObject(SourceTexture, GetTransientPackage()). The following are a number of specific scenarios that will cause a crash, all source assets in these examples were duplicated to a transient package as outlined previously:
Other non crashing cases include:
This way of trying to copy the texture data is very error prone. A much simpler solution would be to duplicate the source texture object over top of the existing one. This is both faster and much more reliable. This can be done with something like the following code:
if (UObject* ExistingAsset = StaticFindObject(nullptr, UsePackage, *NewObjectName, false))
{
UTexture2D* ExistingTexture2D = Cast<UTexture2D>(ExistingAsset);
if (ExistingTexture2D && Options.bOverwriteIfExists)
{
if (GeneratedTexture = DuplicateObject(SourceTexture, ExistingTexture->GetOuter(), ExistingTexture->GetFName()))
{ GeneratedTexture->ClearFlags(RF_Transient); GeneratedTexture->SetFlags(RF_Public | RF_Standalone | RF_Transactional); }
}
}
There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-355953 in the post.