2019-12-26 15:32:37 -05:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
2019-06-11 18:27:07 -04:00
|
|
|
|
2022-11-14 13:18:14 -05:00
|
|
|
#include "VirtualTextureConversionWorker.h"
|
|
|
|
|
|
2019-06-11 18:27:07 -04:00
|
|
|
#include "Engine/Texture2D.h"
|
|
|
|
|
#include "Misc/PackageName.h"
|
|
|
|
|
#include "Materials/Material.h"
|
2022-12-16 16:24:02 -05:00
|
|
|
#include "Materials/MaterialAttributeDefinitionMap.h"
|
2019-06-11 18:27:07 -04:00
|
|
|
#include "Materials/MaterialInstance.h"
|
2022-12-12 13:40:46 -05:00
|
|
|
#include "Materials/MaterialFunction.h"
|
2019-06-11 18:27:07 -04:00
|
|
|
#include "Materials/MaterialFunctionInstance.h"
|
2022-12-12 13:40:46 -05:00
|
|
|
#include "Materials/MaterialFunctionInterface.h"
|
|
|
|
|
#include "Materials/MaterialExpressionTextureSampleParameter.h"
|
2022-12-16 16:24:02 -05:00
|
|
|
#include "MaterialShared.h"
|
2019-06-11 18:27:07 -04:00
|
|
|
#include "MaterialEditor/PreviewMaterial.h"
|
|
|
|
|
#include "Factories/MaterialFactoryNew.h"
|
|
|
|
|
#include "EditorFramework/AssetImportData.h"
|
2022-05-02 18:06:48 -04:00
|
|
|
#include "AssetRegistry/AssetRegistryModule.h"
|
2019-06-11 18:27:07 -04:00
|
|
|
#include "ObjectTools.h"
|
|
|
|
|
|
|
|
|
|
#include "Editor.h"
|
|
|
|
|
#include "Misc/ScopedSlowTask.h"
|
|
|
|
|
#include "EditorSupportDelegates.h"
|
|
|
|
|
#include "MaterialGraph/MaterialGraph.h"
|
|
|
|
|
#include "MaterialEditingLibrary.h"
|
2022-11-14 13:18:14 -05:00
|
|
|
#include "AssetRegistry/AssetRegistryHelpers.h"
|
2022-10-26 16:22:34 -04:00
|
|
|
#include "UObject/UObjectIterator.h"
|
2019-06-11 18:27:07 -04:00
|
|
|
|
|
|
|
|
#define LOCTEXT_NAMESPACE "AssetVTConversion"
|
|
|
|
|
|
|
|
|
|
DEFINE_LOG_CATEGORY_STATIC(LogVirtualTextureConversion, Log, All);
|
|
|
|
|
|
2022-11-14 13:18:53 -05:00
|
|
|
namespace VTConversionWorkerUtil
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
2022-11-14 13:18:53 -05:00
|
|
|
template <class T> void GetReferencersOfType(UObject *Object, TArray<T*> &OutObjects)
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
2022-11-14 13:18:53 -05:00
|
|
|
TArray<FAssetData> OutAssetDatas;
|
|
|
|
|
UAssetRegistryHelpers::FindReferencersOfAssetOfClass(Object, { T::StaticClass() }, OutAssetDatas);
|
2019-06-11 18:27:07 -04:00
|
|
|
|
2022-11-14 13:18:53 -05:00
|
|
|
FScopedSlowTask SlowTask(OutAssetDatas.Num(), LOCTEXT("ConvertToVT_Progress_LoadingObjects", "Loading Objects..."));
|
2019-06-11 18:27:07 -04:00
|
|
|
|
2022-11-14 13:18:53 -05:00
|
|
|
for (auto Data : OutAssetDatas)
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
2022-11-14 13:18:53 -05:00
|
|
|
SlowTask.EnterProgressFrame();
|
2022-11-17 00:30:05 -05:00
|
|
|
if (Data.IsInstanceOf(T::StaticClass()))
|
2022-11-14 13:18:53 -05:00
|
|
|
{
|
2022-11-17 00:30:05 -05:00
|
|
|
T *IsOk = Cast<T>(Data.GetAsset());
|
|
|
|
|
if (IsOk != nullptr)
|
|
|
|
|
{
|
|
|
|
|
OutObjects.Add(IsOk);
|
|
|
|
|
}
|
2022-11-14 13:18:53 -05:00
|
|
|
}
|
2019-06-11 18:27:07 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void GetPreviewMaterials(UTexture2D* InTexture, TArray<UMaterialInterface*>& OutMaterials)
|
|
|
|
|
{
|
|
|
|
|
for (TObjectIterator<UPreviewMaterial> It; It; ++It)
|
|
|
|
|
{
|
|
|
|
|
UMaterial* Material = *It;
|
|
|
|
|
for (uint32 PropertyIndex = 0u; PropertyIndex < MP_MAX; ++PropertyIndex)
|
|
|
|
|
{
|
|
|
|
|
const EMaterialProperty PropertyToValidate = (EMaterialProperty)PropertyIndex;
|
|
|
|
|
if (Material->IsTextureReferencedByProperty(PropertyToValidate, InTexture))
|
|
|
|
|
{
|
|
|
|
|
OutMaterials.Add(Material);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IsVirtualTextureValidForMaterial(UMaterialInterface* InMaterial, UTexture2D* InTexture)
|
|
|
|
|
{
|
|
|
|
|
for (uint32 PropertyIndex = 0u; PropertyIndex < MP_MAX; ++PropertyIndex)
|
|
|
|
|
{
|
|
|
|
|
const EMaterialProperty PropertyToValidate = (EMaterialProperty)PropertyIndex;
|
|
|
|
|
const EShaderFrequency ShaderFrequencyToValidate = FMaterialAttributeDefinitionMap::GetShaderFrequency(PropertyToValidate);
|
|
|
|
|
if (PropertyToValidate == MP_OpacityMask || ShaderFrequencyToValidate != SF_Pixel)
|
|
|
|
|
{
|
|
|
|
|
// see if the texture is referenced by a property that doesn't support virtual texture access
|
|
|
|
|
if (InMaterial->IsTextureReferencedByProperty(PropertyToValidate, InTexture))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-14 13:18:14 -05:00
|
|
|
void FVirtualTextureConversionWorker::AddReferencedObjects( FReferenceCollector& Collector )
|
2020-05-05 15:05:40 -04:00
|
|
|
{
|
|
|
|
|
Collector.AddReferencedObjects( UserTextures );
|
|
|
|
|
Collector.AddReferencedObjects( Textures );
|
|
|
|
|
Collector.AddReferencedObjects( Materials );
|
|
|
|
|
Collector.AddReferencedObjects( Functions );
|
|
|
|
|
Collector.AddReferencedObjects( SizeRejectedTextures );
|
|
|
|
|
Collector.AddReferencedObjects( SizeRejectedTextures );
|
|
|
|
|
Collector.AddReferencedObjects( MaterialRejectedTextures );
|
|
|
|
|
|
2023-05-16 10:52:49 -04:00
|
|
|
for (auto& KV : AuditTrail)
|
|
|
|
|
{
|
|
|
|
|
Collector.AddReferencedObject(KV.Key);
|
|
|
|
|
}
|
2020-05-05 15:05:40 -04:00
|
|
|
}
|
|
|
|
|
|
2023-03-29 13:04:29 -04:00
|
|
|
void FVirtualTextureConversionWorker::FindAllTexturesAndMaterials_Iteration(TSet<UMaterial*>& InAffectedMaterials,
|
|
|
|
|
TSet<UMaterialFunctionInterface*>& InAffectedFunctions,
|
|
|
|
|
TSet<UTexture2D*>& InAffectedTextures,
|
2023-05-16 10:52:49 -04:00
|
|
|
TSet<TObjectPtr<UTexture2D>>& InInvalidTextures,
|
2019-06-11 18:27:07 -04:00
|
|
|
FScopedSlowTask& Task)
|
|
|
|
|
{
|
|
|
|
|
TArray<UMaterialInterface *>MaterialInferfaces; // All parents and instances
|
|
|
|
|
TArray<UMaterialInterface *>MaterialHeap; // Temporary work heap
|
|
|
|
|
TArray<UMaterialFunctionInterface *>FunctionInferfaces; // All parents and instances
|
|
|
|
|
TArray<UMaterialFunctionInterface *>FunctionHeap; // Temporary work heap
|
2023-03-29 13:04:29 -04:00
|
|
|
TMap<UMaterial*, TSet<FMaterialParameterInfo>> ParametersToVtIze;
|
|
|
|
|
TMap<UMaterialFunctionInterface*, TSet<FMaterialParameterInfo>> FunctionParametersToVtIze;
|
2019-06-11 18:27:07 -04:00
|
|
|
|
|
|
|
|
// Find all materials that reference the passed in textures
|
|
|
|
|
// This will also load these materials.
|
|
|
|
|
TArray<UMaterialInterface *> MaterialsUsedByAffectedTextures;
|
2023-03-29 13:04:29 -04:00
|
|
|
for (TSet<UTexture2D*>::TIterator TextureIter(InAffectedTextures); TextureIter; ++TextureIter)
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
2023-03-29 13:04:29 -04:00
|
|
|
UTexture2D* Tex2D = *TextureIter;
|
2019-06-11 18:27:07 -04:00
|
|
|
|
|
|
|
|
Task.EnterProgressFrame();
|
|
|
|
|
TArray<UMaterialInterface *> MaterialsUsingTexture;
|
2022-11-14 13:18:53 -05:00
|
|
|
VTConversionWorkerUtil::GetReferencersOfType(Tex2D, MaterialsUsingTexture);
|
2019-06-11 18:27:07 -04:00
|
|
|
|
|
|
|
|
/*for (auto Material : MaterialsUsingTexture)
|
|
|
|
|
{
|
|
|
|
|
AuditTrail.Add(Material, FAuditTrail(
|
|
|
|
|
Tex2D,
|
|
|
|
|
FString::Printf(TEXT("references texture"))
|
|
|
|
|
));
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
// Check all materials using texture, make sure we're able to convert this texture
|
|
|
|
|
bool bIsVirtualTextureValid = true;
|
|
|
|
|
for (UMaterialInterface* Material : MaterialsUsingTexture)
|
|
|
|
|
{
|
2019-08-01 18:07:08 -04:00
|
|
|
if (!bConvertBackward && !IsVirtualTextureValidForMaterial(Material, Tex2D))
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
|
|
|
|
AuditTrail.Add(Tex2D, FAuditTrail(
|
|
|
|
|
Material,
|
|
|
|
|
TEXT("does not support VT usage on material")));
|
|
|
|
|
bIsVirtualTextureValid = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bIsVirtualTextureValid)
|
|
|
|
|
{
|
|
|
|
|
// If this is an engine texture, we'll make a copy and update any needed references to point to the new copy
|
|
|
|
|
// since we're not changing the original texture, we don't need to bring in any additional dependencies
|
|
|
|
|
// Non-power-2 textures won't convert to VT, don't bring any dependencies for them
|
|
|
|
|
if (!Tex2D->GetPathName().StartsWith("/Engine/") &&
|
|
|
|
|
(Tex2D->Source.IsPowerOfTwo() || Tex2D->PowerOfTwoMode != ETexturePowerOfTwoSetting::None))
|
|
|
|
|
{
|
|
|
|
|
// Also get any preview materials that reference the given texture
|
|
|
|
|
// We need to convert these to ensure any active material editors remain valid
|
|
|
|
|
GetPreviewMaterials(Tex2D, MaterialsUsedByAffectedTextures);
|
|
|
|
|
|
|
|
|
|
MaterialsUsedByAffectedTextures.Append(MaterialsUsingTexture);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-03-29 13:04:29 -04:00
|
|
|
TextureIter.RemoveCurrent();
|
2019-06-11 18:27:07 -04:00
|
|
|
InInvalidTextures.Add(Tex2D);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find all materials that reference the passed in functions
|
|
|
|
|
// This will also load these materials.
|
2023-03-29 13:04:29 -04:00
|
|
|
for (UMaterialFunctionInterface* Func : InAffectedFunctions)
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
|
|
|
|
Task.EnterProgressFrame();
|
|
|
|
|
TArray<UMaterialInterface *> MaterialsUsingFunction;
|
2022-11-14 13:18:53 -05:00
|
|
|
VTConversionWorkerUtil::GetReferencersOfType(Func, MaterialsUsingFunction);
|
2019-06-11 18:27:07 -04:00
|
|
|
|
|
|
|
|
/*for (auto Material : MaterialsUsingFunction)
|
|
|
|
|
{
|
|
|
|
|
AuditTrail.Add(Material, FAuditTrail(
|
|
|
|
|
Func,
|
|
|
|
|
FString::Printf(TEXT("references function"))
|
|
|
|
|
));
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
MaterialsUsedByAffectedTextures.Append(MaterialsUsingFunction);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find all the root materials of the found instances and add them to our
|
|
|
|
|
// working lists.
|
|
|
|
|
for (UMaterialInterface *If : MaterialsUsedByAffectedTextures)
|
|
|
|
|
{
|
|
|
|
|
// It's a material?
|
|
|
|
|
UMaterial *Material = Cast<UMaterial>(If);
|
|
|
|
|
|
|
|
|
|
// It's a material instance? we're only interested in it's root for now
|
|
|
|
|
UMaterialInstance *MaterialInstance = Cast<UMaterialInstance>(If);
|
|
|
|
|
if (MaterialInstance != nullptr)
|
|
|
|
|
{
|
|
|
|
|
Material = MaterialInstance->GetMaterial();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
check(Material); // It's something else entirely??
|
|
|
|
|
MaterialInferfaces.AddUnique(Material);
|
|
|
|
|
MaterialHeap.AddUnique(Material);
|
2023-03-29 13:04:29 -04:00
|
|
|
bool bAlreadyExists;
|
|
|
|
|
InAffectedMaterials.Add(Material, &bAlreadyExists);
|
|
|
|
|
if (!bAlreadyExists)
|
|
|
|
|
{
|
|
|
|
|
AuditTrail.Add(Material, FAuditTrail(
|
|
|
|
|
If,
|
|
|
|
|
FString::Printf(TEXT("is the child of"))
|
|
|
|
|
));
|
|
|
|
|
}
|
2019-06-11 18:27:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We now have a set of "root" materials which will be affected by changing InTextures to VT.
|
|
|
|
|
// Now find all children of these materials which will also be affected trough parameters now requiring VT textures being set on them.
|
|
|
|
|
// This will again load any child instances and their dependencies which aren't loaded yet
|
|
|
|
|
TArray<UMaterialInterface *>VisitedMaterials;
|
|
|
|
|
|
|
|
|
|
while (MaterialHeap.Num() > 0)
|
|
|
|
|
{
|
|
|
|
|
UMaterialInterface *ParentMaterial = MaterialHeap[0];
|
|
|
|
|
MaterialHeap.RemoveAt(0);
|
|
|
|
|
|
|
|
|
|
if (VisitedMaterials.Contains(ParentMaterial))
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogVirtualTextureConversion, Display, TEXT("Circular inheritance chain!? %s"), *ParentMaterial->GetName());
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VisitedMaterials.Add(ParentMaterial);
|
|
|
|
|
|
|
|
|
|
// Check all parameters of the current material. If they reference a texture
|
|
|
|
|
// we want to convert to VT flag the parameter (this will then cause all textures assigned to this parameter to convert to vt as well)
|
|
|
|
|
TArray<FMaterialParameterInfo> ParameterInfos;
|
|
|
|
|
TArray<FGuid> ParameterGuids;
|
|
|
|
|
ParentMaterial->GetAllTextureParameterInfo(ParameterInfos, ParameterGuids);
|
|
|
|
|
|
2023-03-29 13:04:29 -04:00
|
|
|
for (FMaterialParameterInfo& ParamInfo : ParameterInfos)
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
2020-07-06 18:58:26 -04:00
|
|
|
UTexture *ParamValue = nullptr;
|
|
|
|
|
if (ParentMaterial->GetTextureParameterValue(ParamInfo, ParamValue))
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
2020-07-06 18:58:26 -04:00
|
|
|
UTexture2D *ParamValue2D = Cast<UTexture2D>(ParamValue);
|
|
|
|
|
if (ParamValue2D != nullptr)
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
2020-07-06 18:58:26 -04:00
|
|
|
if (InAffectedTextures.Contains(ParamValue2D))
|
|
|
|
|
{
|
|
|
|
|
//UE_LOG(LogVirtualTextureConversion, Display, TEXT("Adding parameter %s because it references %s on %s >> %s"), *ParamInfo.Name.ToString(), *ParamValue2D->GetPathName(), *ParentMaterial->GetMaterial()->GetPathName(), *ParentMaterial->GetPathName());
|
|
|
|
|
ParametersToVtIze.FindOrAdd(ParentMaterial->GetMaterial()).Add(ParamInfo);
|
|
|
|
|
}
|
2019-06-11 18:27:07 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find all direct children of this material (children of children will be discovered later by pushing these children on the MaterialHeap).
|
|
|
|
|
TArray<UMaterialInstance*> ParentMaterialInstances;
|
|
|
|
|
Task.EnterProgressFrame();
|
2022-11-14 13:18:53 -05:00
|
|
|
VTConversionWorkerUtil::GetReferencersOfType(ParentMaterial, ParentMaterialInstances);
|
2019-06-11 18:27:07 -04:00
|
|
|
|
|
|
|
|
for (auto MaterialInstance : ParentMaterialInstances)
|
|
|
|
|
{
|
|
|
|
|
//MaterialInstances.AddUnique(MaterialInstance);
|
|
|
|
|
MaterialInferfaces.AddUnique(MaterialInstance);
|
|
|
|
|
//InstancesForMaterial.FindOrAdd(MaterialInstance->GetMaterial()).AddUnique(MaterialInstance);
|
|
|
|
|
|
|
|
|
|
// Push on the heap to check materials referencing us recursively
|
|
|
|
|
MaterialHeap.AddUnique(MaterialInstance);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// We know have a set of root materials and a set of properties to convert to VT
|
|
|
|
|
// Find all textures referenced by these properties
|
|
|
|
|
// These new textures could in turn be referenced by other materials (not in the inheritance chain)
|
|
|
|
|
// which is why we have to run this discovery process iteratively until we don't discover any new
|
|
|
|
|
// materials or textures.
|
|
|
|
|
|
|
|
|
|
for (UMaterialInterface *If : MaterialInferfaces)
|
|
|
|
|
{
|
|
|
|
|
UMaterial *Mat = If->GetMaterial();
|
|
|
|
|
for (const FMaterialParameterInfo &Parameter : ParametersToVtIze.FindOrAdd(Mat))
|
|
|
|
|
{
|
2020-07-06 18:58:26 -04:00
|
|
|
UTexture *Tex = nullptr;
|
|
|
|
|
if (If->GetTextureParameterValue(Parameter, Tex))
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
2020-07-06 18:58:26 -04:00
|
|
|
UTexture2D *Tex2D = Cast<UTexture2D>(Tex);
|
|
|
|
|
if (Tex2D && !Tex2D->VirtualTextureStreaming)
|
|
|
|
|
{
|
2023-03-29 13:04:29 -04:00
|
|
|
bool bAlreadyExists;
|
|
|
|
|
InAffectedTextures.Add(Tex2D, &bAlreadyExists);
|
|
|
|
|
if (!bAlreadyExists)
|
|
|
|
|
{
|
|
|
|
|
AuditTrail.Add(Tex2D, FAuditTrail(
|
|
|
|
|
Mat,
|
|
|
|
|
FString::Printf(TEXT("set on parameter %s in instance %s of material"), *Parameter.Name.ToString(), *If->GetName())
|
|
|
|
|
));
|
|
|
|
|
}
|
2020-07-06 18:58:26 -04:00
|
|
|
}
|
2019-06-11 18:27:07 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Pretty much the same again but now for material functions....
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
// Find all materials functions that directly reference the passed in textures
|
|
|
|
|
TArray<UMaterialFunctionInterface *> FunctionsUsedByAffectedTextures;
|
2023-03-29 13:04:29 -04:00
|
|
|
for (UTexture2D* Tex2D : InAffectedTextures)
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
|
|
|
|
Task.EnterProgressFrame();
|
|
|
|
|
if (!Tex2D->GetPathName().StartsWith("/Engine/"))
|
|
|
|
|
{
|
2022-11-14 13:18:53 -05:00
|
|
|
VTConversionWorkerUtil::GetReferencersOfType(Tex2D, FunctionsUsedByAffectedTextures);
|
2019-06-11 18:27:07 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find all the root function of the found instances and add them to our
|
|
|
|
|
// working lists.
|
|
|
|
|
for (UMaterialFunctionInterface *If : FunctionsUsedByAffectedTextures)
|
|
|
|
|
{
|
|
|
|
|
// It's a material?
|
Restore backed out CL, with fixes.
Also restores follow-up CLs 19973746, 19973782
FStaticParameterSet::MaterialLayers can't be deprecated, since a property with the same name is included via FStaticParameterSetRuntimeData
So instead, FMaterialLayersFunctionsRuntimeData is updated with SerializeFromMismatchedTag, to allow serializing a full FMaterialLayersFunction.
When this happens, the EditorOnly portion is stored in a separate heap allocation, and then transferred to FStaticParameterSet::EditorOnly::MaterialLayers
#preflight 626c3405e31dbb512cef1e98
[Backout] - CL19973745
#fyi bob.tellez
Original CL Desc
-----------------------------------------------------------------
[Backout] - CL19964485
#fyi Ben.Ingram
Original CL Desc
-----------------------------------------------------------------
Add 'Optional' EditorOnly data for UMaterialInterface and UMaterialFunctionInterface
These are separate UObject hierarchies that store editor-only UPROPERTIES, but can be included with cooked content, which allows full editor support.
In principle, all editor-only properties could be moved over. So far, this has been limited to UMaterialExpressions, and data related to material parameters.
FStaticParameterSet, FMaterialLayersParameters, and FMaterialCachedExpressionData have all been split into separate editor-only/non-editor-only classes,
which allows the editor-only portion to be stored on the optional editor-only UObject.
#preflight 626ab21dad56c0cbbea32dc4
#rb jason.nadro, francis.hurteau
#jira FORT-463329
[CL 20043286 by Jason Nadro in ue5-main branch]
2022-05-04 12:21:52 -04:00
|
|
|
UMaterialFunction* Function = If->GetBaseFunction();
|
|
|
|
|
if (Function)
|
2022-04-28 20:08:12 -04:00
|
|
|
{
|
Restore backed out CL, with fixes.
Also restores follow-up CLs 19973746, 19973782
FStaticParameterSet::MaterialLayers can't be deprecated, since a property with the same name is included via FStaticParameterSetRuntimeData
So instead, FMaterialLayersFunctionsRuntimeData is updated with SerializeFromMismatchedTag, to allow serializing a full FMaterialLayersFunction.
When this happens, the EditorOnly portion is stored in a separate heap allocation, and then transferred to FStaticParameterSet::EditorOnly::MaterialLayers
#preflight 626c3405e31dbb512cef1e98
[Backout] - CL19973745
#fyi bob.tellez
Original CL Desc
-----------------------------------------------------------------
[Backout] - CL19964485
#fyi Ben.Ingram
Original CL Desc
-----------------------------------------------------------------
Add 'Optional' EditorOnly data for UMaterialInterface and UMaterialFunctionInterface
These are separate UObject hierarchies that store editor-only UPROPERTIES, but can be included with cooked content, which allows full editor support.
In principle, all editor-only properties could be moved over. So far, this has been limited to UMaterialExpressions, and data related to material parameters.
FStaticParameterSet, FMaterialLayersParameters, and FMaterialCachedExpressionData have all been split into separate editor-only/non-editor-only classes,
which allows the editor-only portion to be stored on the optional editor-only UObject.
#preflight 626ab21dad56c0cbbea32dc4
#rb jason.nadro, francis.hurteau
#jira FORT-463329
[CL 20043286 by Jason Nadro in ue5-main branch]
2022-05-04 12:21:52 -04:00
|
|
|
FunctionInferfaces.AddUnique(Function);
|
|
|
|
|
FunctionHeap.AddUnique(Function);
|
2023-03-29 13:04:29 -04:00
|
|
|
bool bAlreadyExists;
|
|
|
|
|
InAffectedFunctions.Add(Function, &bAlreadyExists);
|
|
|
|
|
if (!bAlreadyExists)
|
|
|
|
|
{
|
|
|
|
|
AuditTrail.Add(Function, FAuditTrail(
|
|
|
|
|
If,
|
|
|
|
|
FString::Printf(TEXT("this is the parent of"))
|
|
|
|
|
));
|
|
|
|
|
}
|
2019-06-11 18:27:07 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We have a second class of functions here. That is functions that don't directly reference any textures of interest
|
|
|
|
|
// but where there are material instances that overrides properties in the textures that do reference textures of interest
|
2023-03-29 13:04:29 -04:00
|
|
|
for (TPair<UMaterial*, TSet<FMaterialParameterInfo>>& MaterialParametersPair : ParametersToVtIze)
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
2023-03-29 13:04:29 -04:00
|
|
|
for (FMaterialParameterInfo& Parameter : MaterialParametersPair.Value)
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
|
|
|
|
TArray<UMaterialFunctionInterface*> DependentFunctions;
|
|
|
|
|
MaterialParametersPair.Key->GetDependentFunctions(DependentFunctions);
|
2023-03-29 13:04:29 -04:00
|
|
|
for (UMaterialFunctionInterface* Function : DependentFunctions)
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
Restore backed out CL, with fixes.
Also restores follow-up CLs 19973746, 19973782
FStaticParameterSet::MaterialLayers can't be deprecated, since a property with the same name is included via FStaticParameterSetRuntimeData
So instead, FMaterialLayersFunctionsRuntimeData is updated with SerializeFromMismatchedTag, to allow serializing a full FMaterialLayersFunction.
When this happens, the EditorOnly portion is stored in a separate heap allocation, and then transferred to FStaticParameterSet::EditorOnly::MaterialLayers
#preflight 626c3405e31dbb512cef1e98
[Backout] - CL19973745
#fyi bob.tellez
Original CL Desc
-----------------------------------------------------------------
[Backout] - CL19964485
#fyi Ben.Ingram
Original CL Desc
-----------------------------------------------------------------
Add 'Optional' EditorOnly data for UMaterialInterface and UMaterialFunctionInterface
These are separate UObject hierarchies that store editor-only UPROPERTIES, but can be included with cooked content, which allows full editor support.
In principle, all editor-only properties could be moved over. So far, this has been limited to UMaterialExpressions, and data related to material parameters.
FStaticParameterSet, FMaterialLayersParameters, and FMaterialCachedExpressionData have all been split into separate editor-only/non-editor-only classes,
which allows the editor-only portion to be stored on the optional editor-only UObject.
#preflight 626ab21dad56c0cbbea32dc4
#rb jason.nadro, francis.hurteau
#jira FORT-463329
[CL 20043286 by Jason Nadro in ue5-main branch]
2022-05-04 12:21:52 -04:00
|
|
|
for (UMaterialExpression* FunctionExpression : Function->GetExpressions())
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
|
|
|
|
if (const UMaterialExpressionTextureSampleParameter* TexParameter = Cast<const UMaterialExpressionTextureSampleParameter>(FunctionExpression))
|
|
|
|
|
{
|
|
|
|
|
if (TexParameter->ParameterName == Parameter.Name)
|
|
|
|
|
{
|
2023-03-29 13:04:29 -04:00
|
|
|
FunctionParametersToVtIze.FindOrAdd(Function->GetBaseFunction()).Add(Parameter);
|
|
|
|
|
InAffectedFunctions.Add(Function->GetBaseFunction());
|
2019-06-11 18:27:07 -04:00
|
|
|
FunctionHeap.AddUnique(Function->GetBaseFunction());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We now have a set of "root" functions which will be affected by changing InTextures to VT.
|
|
|
|
|
// Now find all children of these materials which will also be affected trough parameters now requiring VT textures being set on them.
|
|
|
|
|
// This will again load any child instances and their dependencies which aren't loaded yet
|
|
|
|
|
while (FunctionHeap.Num() > 0)
|
|
|
|
|
{
|
|
|
|
|
UMaterialFunctionInterface *ParentFunction = FunctionHeap[0];
|
|
|
|
|
FunctionHeap.RemoveAt(0);
|
|
|
|
|
{
|
2021-10-27 15:14:40 -04:00
|
|
|
UMaterialFunctionInstance* FunctionInstance = Cast<UMaterialFunctionInstance>(ParentFunction);
|
|
|
|
|
if (FunctionInstance)
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
2021-10-27 15:14:40 -04:00
|
|
|
// Check all parameters of the current material. If they reference a texture
|
|
|
|
|
// we want to convert to VT flag the parameter (this will then cause all textures assigned to this parameter to convert to vt as well)
|
|
|
|
|
for (const FTextureParameterValue& TextureParameter : FunctionInstance->TextureParameterValues)
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
2021-10-27 15:14:40 -04:00
|
|
|
UTexture2D* ParamValue2D = Cast<UTexture2D>(TextureParameter.ParameterValue);
|
|
|
|
|
if (InAffectedTextures.Contains(ParamValue2D))
|
|
|
|
|
{
|
|
|
|
|
FunctionParametersToVtIze.FindOrAdd(ParentFunction->GetBaseFunction()).Add(TextureParameter.ParameterInfo);
|
|
|
|
|
}
|
2019-06-11 18:27:07 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find all direct children of this function (children of children will be discovered later by pushing these children on the FunctionHeap).
|
|
|
|
|
TArray<UMaterialFunctionInstance*> ParentFunctionInstances;
|
|
|
|
|
Task.EnterProgressFrame();
|
2022-11-14 13:18:53 -05:00
|
|
|
VTConversionWorkerUtil::GetReferencersOfType(ParentFunction, ParentFunctionInstances);
|
2019-06-11 18:27:07 -04:00
|
|
|
|
|
|
|
|
for (auto FunctionInstance : ParentFunctionInstances)
|
|
|
|
|
{
|
|
|
|
|
FunctionInferfaces.AddUnique(FunctionInstance);
|
|
|
|
|
|
|
|
|
|
// Push on the heap to check materials referencing us recursively
|
|
|
|
|
FunctionHeap.AddUnique(FunctionInstance);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We know have a set of root functions and a set of properties to convert to VT
|
|
|
|
|
// Find all textures referenced by these properties
|
|
|
|
|
// These new textures could in turn be referenced by other materials and or functions (not in the inheritance chain)
|
|
|
|
|
// which is why we have to run this discovery process iteratively until we don't discover any new
|
|
|
|
|
// materials or textures.
|
|
|
|
|
|
|
|
|
|
for (UMaterialFunctionInterface *If : FunctionInferfaces)
|
|
|
|
|
{
|
|
|
|
|
UMaterialFunctionInterface *Func = If->GetBaseFunction();
|
|
|
|
|
for (const FMaterialParameterInfo &Parameter : FunctionParametersToVtIze.FindOrAdd(Func))
|
|
|
|
|
{
|
|
|
|
|
UTexture *Tex = nullptr;
|
|
|
|
|
If->OverrideNamedTextureParameter(Parameter, Tex);
|
|
|
|
|
UTexture2D *Tex2D = Cast<UTexture2D>(Tex);
|
|
|
|
|
if (Tex2D && !Tex2D->VirtualTextureStreaming)
|
|
|
|
|
{
|
2023-03-29 13:04:29 -04:00
|
|
|
bool bAlreadyExists;
|
|
|
|
|
InAffectedTextures.Add(Tex2D, &bAlreadyExists);
|
|
|
|
|
if (!bAlreadyExists)
|
|
|
|
|
{
|
|
|
|
|
AuditTrail.Add(Tex2D, FAuditTrail(
|
|
|
|
|
Func,
|
|
|
|
|
FString::Printf(TEXT("set on parameter %s in instance %s"), *Parameter.Name.ToString(), *If->GetPathName())
|
|
|
|
|
));
|
|
|
|
|
}
|
2019-06-11 18:27:07 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-16 10:52:49 -04:00
|
|
|
void FVirtualTextureConversionWorker::FindAllTexturesAndMaterials(TArray<TObjectPtr<UMaterial >> &OutAffectedMaterials, TArray<TObjectPtr<UMaterialFunctionInterface >> &OutAffectedFunctions, TArray<TObjectPtr<UTexture2D >> &OutAffectedTextures)
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
|
|
|
|
FScopedSlowTask SlowTask(1000.0f, LOCTEXT("ConvertToVT_Progress_FindAllTexturesAndMaterials", "Finding Textures and Materials..."));
|
2023-03-29 13:04:29 -04:00
|
|
|
TSet<UMaterial*> AffectedMaterials;
|
|
|
|
|
TSet<UMaterialFunctionInterface*> AffectedFunctions;
|
|
|
|
|
TSet<UTexture2D*> AffectedTextures;
|
2023-05-16 10:52:49 -04:00
|
|
|
AffectedMaterials.Append(ObjectPtrDecay(OutAffectedMaterials));
|
|
|
|
|
AffectedFunctions.Append(ObjectPtrDecay(OutAffectedFunctions));
|
|
|
|
|
AffectedTextures.Append(ObjectPtrDecay(OutAffectedTextures));
|
2023-03-29 13:04:29 -04:00
|
|
|
int LastNumMaterials = AffectedMaterials.Num();
|
|
|
|
|
int LastNumTextures = AffectedTextures.Num();
|
|
|
|
|
int LastNumFunctions = AffectedFunctions.Num();
|
2019-06-11 18:27:07 -04:00
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
2023-03-29 13:04:29 -04:00
|
|
|
FindAllTexturesAndMaterials_Iteration(AffectedMaterials, AffectedFunctions, AffectedTextures, MaterialRejectedTextures, SlowTask);
|
|
|
|
|
if (AffectedMaterials.Num() == LastNumMaterials && AffectedTextures.Num() == LastNumTextures && AffectedFunctions.Num() == LastNumFunctions)
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
2023-03-29 13:04:29 -04:00
|
|
|
break;
|
2019-06-11 18:27:07 -04:00
|
|
|
}
|
|
|
|
|
|
2023-04-01 02:37:58 -04:00
|
|
|
LastNumMaterials = AffectedMaterials.Num();
|
|
|
|
|
LastNumTextures = AffectedTextures.Num();
|
|
|
|
|
LastNumFunctions = AffectedFunctions.Num();
|
2019-06-11 18:27:07 -04:00
|
|
|
}
|
2023-05-16 10:52:49 -04:00
|
|
|
OutAffectedMaterials = ObjectPtrWrap(AffectedMaterials.Array());
|
|
|
|
|
OutAffectedFunctions = ObjectPtrWrap(AffectedFunctions.Array());
|
|
|
|
|
OutAffectedTextures = ObjectPtrWrap(AffectedTextures.Array());
|
2019-06-11 18:27:07 -04:00
|
|
|
}
|
|
|
|
|
|
2022-11-14 13:18:14 -05:00
|
|
|
void FVirtualTextureConversionWorker::FilterList(int32 SizeThreshold)
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
2019-06-18 16:41:05 -04:00
|
|
|
FScopedSlowTask SlowTask(1.0f, LOCTEXT("ConvertToVT_Progress_FindingTextures", "Finding textures to convert..."));
|
2019-06-11 18:27:07 -04:00
|
|
|
SlowTask.MakeDialog();
|
|
|
|
|
|
|
|
|
|
Textures.Empty();
|
|
|
|
|
Materials.Empty();
|
|
|
|
|
Functions.Empty();
|
|
|
|
|
SizeRejectedTextures.Empty();
|
|
|
|
|
|
|
|
|
|
for (UTexture2D *Texture : UserTextures)
|
|
|
|
|
{
|
|
|
|
|
if (Texture->GetSizeX()*Texture->GetSizeY() >= SizeThreshold * SizeThreshold)
|
|
|
|
|
{
|
|
|
|
|
Textures.Add(Texture);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SizeRejectedTextures.Add(Texture);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SlowTask.EnterProgressFrame();
|
|
|
|
|
FindAllTexturesAndMaterials(Materials, Functions, Textures);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void MarkTextureExpressionModified(UMaterialExpressionTextureBase* Expression)
|
|
|
|
|
{
|
|
|
|
|
FPropertyChangedEvent SamplerTypeChangeEvent(UMaterialExpressionTextureBase::StaticClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UMaterialExpressionTextureBase, SamplerType)));
|
|
|
|
|
FPropertyChangedEvent TextureChangeEvent(UMaterialExpressionTextureBase::StaticClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UMaterialExpressionTextureBase, Texture)));
|
|
|
|
|
|
|
|
|
|
Expression->Modify();
|
|
|
|
|
|
|
|
|
|
// Nofity that we changed SamplerType
|
|
|
|
|
Expression->PostEditChangeProperty(SamplerTypeChangeEvent);
|
|
|
|
|
|
|
|
|
|
// Also notify that we changed Texture (technically didn't modify this property)
|
|
|
|
|
// This way code in FMaterialExpressionTextureBaseDetails will see the event, and refresh the list of valid sampler types for the updated texture
|
|
|
|
|
Expression->PostEditChangeProperty(TextureChangeEvent);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-14 13:18:14 -05:00
|
|
|
void FVirtualTextureConversionWorker::DoConvert()
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
2019-08-01 18:07:08 -04:00
|
|
|
const bool bVirtualTextureEnable = !bConvertBackward;
|
2019-06-11 18:27:07 -04:00
|
|
|
|
2019-06-18 16:41:05 -04:00
|
|
|
FScopedSlowTask SlowTask(2.0f, LOCTEXT("ConvertToVT_Progress_ConvertingTexturesAndMaterials", "Converting textures and materials..."));
|
2019-06-11 18:27:07 -04:00
|
|
|
SlowTask.MakeDialog();
|
|
|
|
|
|
|
|
|
|
TMap<UTexture2D*, UTexture2D*> EngineTextureToCopyMap;
|
|
|
|
|
|
|
|
|
|
UE_LOG(LogVirtualTextureConversion, Display, TEXT("Beginning conversion..."));
|
|
|
|
|
SlowTask.EnterProgressFrame();
|
|
|
|
|
{
|
|
|
|
|
FScopedSlowTask TextureTask(Textures.Num(), LOCTEXT("ConvertToVT_Progress_TextureTask", "Updating textures..."));
|
|
|
|
|
|
|
|
|
|
for (UTexture2D *Tex : Textures)
|
|
|
|
|
{
|
|
|
|
|
UTexture2D* TextureToUpdate = Tex;
|
2021-09-30 17:38:53 -04:00
|
|
|
if (TextureToUpdate->GetPathName().StartsWith(TEXT("/Engine/")) && TextureToUpdate->GetPackage() != GetTransientPackage())
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
|
|
|
|
// rather than modify engine content, create a copy and update that
|
|
|
|
|
// any materials that we modify will be updated to point to the copy
|
|
|
|
|
ObjectTools::FPackageGroupName PGN;
|
|
|
|
|
PGN.GroupName = TEXT("");
|
|
|
|
|
PGN.ObjectName = Tex->GetName().Append(TEXT("_VT"));
|
|
|
|
|
PGN.PackageName = TEXT("/Game/Textures/");
|
|
|
|
|
PGN.PackageName.Append(PGN.ObjectName);
|
|
|
|
|
|
|
|
|
|
UPackage* ExistingPackage = FindPackage(NULL, *PGN.PackageName);
|
|
|
|
|
UTexture2D* DuplicateTexture = nullptr;
|
|
|
|
|
if (ExistingPackage)
|
|
|
|
|
{
|
|
|
|
|
UObject* DuplicateObject = StaticFindObject(UTexture2D::StaticClass(), ExistingPackage, *PGN.ObjectName);
|
|
|
|
|
if (DuplicateObject)
|
|
|
|
|
{
|
|
|
|
|
DuplicateTexture = CastChecked<UTexture2D>(DuplicateObject);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!DuplicateTexture || DuplicateTexture->VirtualTextureStreaming != bVirtualTextureEnable)
|
|
|
|
|
{
|
|
|
|
|
// TODO - overwrite previous texture (if it exists), or should we always generate a unique name?
|
|
|
|
|
TSet<UPackage*> ObjectsUserRefusedToFullyLoad;
|
|
|
|
|
UObject* DuplicateObject = ObjectTools::DuplicateSingleObject(Tex, PGN, ObjectsUserRefusedToFullyLoad, false);
|
|
|
|
|
if (DuplicateObject)
|
|
|
|
|
{
|
|
|
|
|
DuplicateTexture = CastChecked<UTexture2D>(DuplicateObject);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TextureToUpdate = DuplicateTexture;
|
|
|
|
|
EngineTextureToCopyMap.Add(Tex, TextureToUpdate);
|
|
|
|
|
if (!TextureToUpdate)
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogVirtualTextureConversion, Warning, TEXT("Failed to duplicate engine texture %s"), *Tex->GetPathName());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TextureToUpdate)
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogVirtualTextureConversion, Display, TEXT("Texture %s"), *TextureToUpdate->GetName());
|
|
|
|
|
TextureTask.EnterProgressFrame();
|
|
|
|
|
|
2020-12-01 18:20:19 -04:00
|
|
|
if (TextureToUpdate->VirtualTextureStreaming != bVirtualTextureEnable)
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
|
|
|
|
FPropertyChangedEvent PropertyChangeEvent(UTexture::StaticClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UTexture, VirtualTextureStreaming)));
|
|
|
|
|
TextureToUpdate->Modify();
|
2020-12-01 18:20:19 -04:00
|
|
|
TextureToUpdate->VirtualTextureStreaming = bVirtualTextureEnable;
|
2019-06-11 18:27:07 -04:00
|
|
|
TextureToUpdate->PostEditChangeProperty(PropertyChangeEvent);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SlowTask.EnterProgressFrame();
|
|
|
|
|
{
|
|
|
|
|
FScopedSlowTask MaterialTask(Materials.Num() + Functions.Num(), LOCTEXT("ConvertToVT_Progress_MaterialTask", "Updating materials..."));
|
|
|
|
|
FMaterialUpdateContext UpdateContext;
|
|
|
|
|
|
|
|
|
|
TMap<UMaterialFunctionInterface*, TArray<UMaterial*>> FunctionToMaterialMap;
|
|
|
|
|
|
|
|
|
|
for (UMaterial *Mat : Materials)
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogVirtualTextureConversion, Display, TEXT("Material %s"), *Mat->GetName());
|
|
|
|
|
|
|
|
|
|
MaterialTask.EnterProgressFrame();
|
|
|
|
|
|
|
|
|
|
bool MatModified = false;
|
Restore backed out CL, with fixes.
Also restores follow-up CLs 19973746, 19973782
FStaticParameterSet::MaterialLayers can't be deprecated, since a property with the same name is included via FStaticParameterSetRuntimeData
So instead, FMaterialLayersFunctionsRuntimeData is updated with SerializeFromMismatchedTag, to allow serializing a full FMaterialLayersFunction.
When this happens, the EditorOnly portion is stored in a separate heap allocation, and then transferred to FStaticParameterSet::EditorOnly::MaterialLayers
#preflight 626c3405e31dbb512cef1e98
[Backout] - CL19973745
#fyi bob.tellez
Original CL Desc
-----------------------------------------------------------------
[Backout] - CL19964485
#fyi Ben.Ingram
Original CL Desc
-----------------------------------------------------------------
Add 'Optional' EditorOnly data for UMaterialInterface and UMaterialFunctionInterface
These are separate UObject hierarchies that store editor-only UPROPERTIES, but can be included with cooked content, which allows full editor support.
In principle, all editor-only properties could be moved over. So far, this has been limited to UMaterialExpressions, and data related to material parameters.
FStaticParameterSet, FMaterialLayersParameters, and FMaterialCachedExpressionData have all been split into separate editor-only/non-editor-only classes,
which allows the editor-only portion to be stored on the optional editor-only UObject.
#preflight 626ab21dad56c0cbbea32dc4
#rb jason.nadro, francis.hurteau
#jira FORT-463329
[CL 20043286 by Jason Nadro in ue5-main branch]
2022-05-04 12:21:52 -04:00
|
|
|
for (UMaterialExpression *Expr : Mat->GetExpressions())
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
|
|
|
|
UMaterialExpressionTextureBase *TexExpr = Cast<UMaterialExpressionTextureBase>(Expr);
|
|
|
|
|
if (TexExpr)
|
|
|
|
|
{
|
|
|
|
|
if (Textures.Contains(TexExpr->Texture))
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogVirtualTextureConversion, Display, TEXT("Adjusting sampler %s."), *TexExpr->GetName());
|
|
|
|
|
UTexture2D** FoundTextureCopy = EngineTextureToCopyMap.Find(CastChecked<UTexture2D>(TexExpr->Texture));
|
|
|
|
|
UTexture2D* TextureCopy = nullptr;
|
|
|
|
|
bool bShouldUpdateMaterial = true;
|
|
|
|
|
if (FoundTextureCopy)
|
|
|
|
|
{
|
|
|
|
|
TextureCopy = *FoundTextureCopy;
|
|
|
|
|
if (TextureCopy)
|
|
|
|
|
{
|
|
|
|
|
TexExpr->Texture = TextureCopy;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// nullptr was set in EngineTextureToCopyMap....this means we failed to create copy of engine texture for this resource
|
|
|
|
|
// bail on updating the material in this case
|
|
|
|
|
bShouldUpdateMaterial = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto OldType = TexExpr->SamplerType;
|
|
|
|
|
if (bShouldUpdateMaterial)
|
|
|
|
|
{
|
|
|
|
|
TexExpr->AutoSetSampleType();
|
|
|
|
|
}
|
|
|
|
|
if (TextureCopy != nullptr || OldType != TexExpr->SamplerType)
|
|
|
|
|
{
|
|
|
|
|
MarkTextureExpressionModified(TexExpr);
|
|
|
|
|
MatModified = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TArray<UMaterialFunctionInterface *>MaterialFunctions;
|
|
|
|
|
Mat->GetDependentFunctions(MaterialFunctions);
|
|
|
|
|
for (auto Function : MaterialFunctions)
|
|
|
|
|
{
|
|
|
|
|
FunctionToMaterialMap.FindOrAdd(Function).AddUnique(Mat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (MatModified)
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogVirtualTextureConversion, Display, TEXT("Material %s added to update list."), *Mat->GetName());
|
|
|
|
|
UMaterialEditingLibrary::RecompileMaterial(Mat);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogVirtualTextureConversion, Display, TEXT("Material %s was not modified, skipping."), *Mat->GetName());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (UMaterialFunctionInterface *Func : Functions)
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogVirtualTextureConversion, Display, TEXT("Function %s"), *Func->GetName());
|
|
|
|
|
|
|
|
|
|
MaterialTask.EnterProgressFrame();
|
|
|
|
|
|
|
|
|
|
bool FuncModified = false;
|
Restore backed out CL, with fixes.
Also restores follow-up CLs 19973746, 19973782
FStaticParameterSet::MaterialLayers can't be deprecated, since a property with the same name is included via FStaticParameterSetRuntimeData
So instead, FMaterialLayersFunctionsRuntimeData is updated with SerializeFromMismatchedTag, to allow serializing a full FMaterialLayersFunction.
When this happens, the EditorOnly portion is stored in a separate heap allocation, and then transferred to FStaticParameterSet::EditorOnly::MaterialLayers
#preflight 626c3405e31dbb512cef1e98
[Backout] - CL19973745
#fyi bob.tellez
Original CL Desc
-----------------------------------------------------------------
[Backout] - CL19964485
#fyi Ben.Ingram
Original CL Desc
-----------------------------------------------------------------
Add 'Optional' EditorOnly data for UMaterialInterface and UMaterialFunctionInterface
These are separate UObject hierarchies that store editor-only UPROPERTIES, but can be included with cooked content, which allows full editor support.
In principle, all editor-only properties could be moved over. So far, this has been limited to UMaterialExpressions, and data related to material parameters.
FStaticParameterSet, FMaterialLayersParameters, and FMaterialCachedExpressionData have all been split into separate editor-only/non-editor-only classes,
which allows the editor-only portion to be stored on the optional editor-only UObject.
#preflight 626ab21dad56c0cbbea32dc4
#rb jason.nadro, francis.hurteau
#jira FORT-463329
[CL 20043286 by Jason Nadro in ue5-main branch]
2022-05-04 12:21:52 -04:00
|
|
|
for (const TObjectPtr<UMaterialExpression>& Expr : Func->GetExpressions())
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
2021-04-13 15:47:11 -04:00
|
|
|
UMaterialExpressionTextureBase *TexExpr = Cast<UMaterialExpressionTextureBase>(Expr);
|
|
|
|
|
if (TexExpr)
|
2019-06-11 18:27:07 -04:00
|
|
|
{
|
|
|
|
|
if (Textures.Contains(TexExpr->Texture))
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogVirtualTextureConversion, Display, TEXT("Adjusting sampler %s."), *TexExpr->GetName());
|
|
|
|
|
UTexture2D** FoundTextureCopy = EngineTextureToCopyMap.Find(CastChecked<UTexture2D>(TexExpr->Texture));
|
|
|
|
|
UTexture2D* TextureCopy = nullptr;
|
|
|
|
|
bool bShouldUpdateMaterial = true;
|
|
|
|
|
if (FoundTextureCopy)
|
|
|
|
|
{
|
|
|
|
|
TextureCopy = *FoundTextureCopy;
|
|
|
|
|
if (TextureCopy)
|
|
|
|
|
{
|
|
|
|
|
TexExpr->Texture = TextureCopy;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// nullptr was set in EngineTextureToCopyMap....this means we failed to create copy of engine texture for this resource
|
|
|
|
|
// bail on updating the material in this case
|
|
|
|
|
bShouldUpdateMaterial = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto OldType = TexExpr->SamplerType;
|
|
|
|
|
if (bShouldUpdateMaterial)
|
|
|
|
|
{
|
|
|
|
|
TexExpr->AutoSetSampleType();
|
|
|
|
|
}
|
|
|
|
|
if (TextureCopy != nullptr || TexExpr->SamplerType != OldType)
|
|
|
|
|
{
|
|
|
|
|
MarkTextureExpressionModified(TexExpr);
|
|
|
|
|
FuncModified = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (FuncModified)
|
|
|
|
|
{
|
|
|
|
|
UMaterialEditingLibrary::UpdateMaterialFunction(Func, nullptr);
|
|
|
|
|
UE_LOG(LogVirtualTextureConversion, Display, TEXT("Function %s added to update list."), *Func->GetName());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogVirtualTextureConversion, Display, TEXT("Function %s was not modified, skipping."), *Func->GetName());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// update the world's viewports
|
|
|
|
|
UE_LOG(LogVirtualTextureConversion, Display, TEXT("Broadcasting to editor."));
|
|
|
|
|
FEditorDelegates::RefreshEditor.Broadcast();
|
|
|
|
|
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-16 10:52:49 -04:00
|
|
|
#undef LOCTEXT_NAMESPACE
|