Files
2025-05-18 13:04:45 +08:00

306 lines
9.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Item/MetaHumanMaterialPipelineCommon.h"
#include "StructUtils/PropertyBag.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "Engine/Texture.h"
#include "Algo/Find.h"
namespace UE::MetaHuman::MaterialUtils
{
void SetInstanceParameters(
const TArray<FMetaHumanMaterialParameter>& InMaterialParameters,
const TMap<FName, TObjectPtr<class UMaterialInstanceDynamic>>& InMaterialInstanceMapping,
const TArray<FName>& InAvailableSlots,
const FInstancedPropertyBag& InPropertyBag)
{
const UPropertyBag* PropertyBag = InPropertyBag.GetPropertyBagStruct();
if (!PropertyBag)
{
return;
}
for (const FPropertyBagPropertyDesc& PropertyDesc : PropertyBag->GetPropertyDescs())
{
const FMetaHumanMaterialParameter* Parameter = Algo::FindBy(InMaterialParameters, PropertyDesc.Name, &FMetaHumanMaterialParameter::InstanceParameterName);
if (!Parameter)
{
// TODO: log error as this suggests InMaterialParameters have changed since assembly
continue;
}
// Slot names are collected either from slot indices or explicit slot names defined on the parameter
TArray<FName> SlotNames;
switch (Parameter->SlotTarget)
{
case EMetaHumanRuntimeMaterialParameterSlotTarget::SlotNames:
{
SlotNames = Parameter->SlotNames;
break;
}
case EMetaHumanRuntimeMaterialParameterSlotTarget::SlotIndices:
{
for (int32 SlotIndex : Parameter->SlotIndices)
{
if (InAvailableSlots.IsValidIndex(SlotIndex))
{
SlotNames.Add(InAvailableSlots[SlotIndex]);
}
}
break;
}
default:
break;
}
for (const FName SlotName : SlotNames)
{
UMaterialInstanceDynamic* MaterialInstance = nullptr;
if (const TObjectPtr<UMaterialInstanceDynamic>* FoundMaterialInstance = InMaterialInstanceMapping.Find(SlotName))
{
MaterialInstance = *FoundMaterialInstance;
}
if (!MaterialInstance)
{
// TODO: log error. This shouldn't happen
continue;
}
switch (Parameter->ParameterType)
{
case EMetaHumanRuntimeMaterialParameterType::Toggle:
{
const TValueOrError<bool, EPropertyBagResult> Result = InPropertyBag.GetValueBool(PropertyDesc);
if (!Result.HasValue())
{
break;
}
MaterialInstance->SetScalarParameterValueByInfo(Parameter->MaterialParameter, Result.GetValue() ? 1.0f : 0.0f);
}
break;
case EMetaHumanRuntimeMaterialParameterType::Scalar:
{
const TValueOrError<float, EPropertyBagResult> Result = InPropertyBag.GetValueFloat(PropertyDesc);
if (!Result.HasValue())
{
break;
}
MaterialInstance->SetScalarParameterValueByInfo(Parameter->MaterialParameter, Result.GetValue());
}
break;
case EMetaHumanRuntimeMaterialParameterType::Vector:
{
const TValueOrError<FLinearColor*, EPropertyBagResult> Result = InPropertyBag.GetValueStruct<FLinearColor>(PropertyDesc);
if (!Result.HasValue()
&& Result.GetValue() != nullptr)
{
break;
}
MaterialInstance->SetVectorParameterValueByInfo(Parameter->MaterialParameter, *Result.GetValue());
}
break;
case EMetaHumanRuntimeMaterialParameterType::DoubleVector:
case EMetaHumanRuntimeMaterialParameterType::Texture:
{
const TValueOrError<UObject*, EPropertyBagResult> Result = InPropertyBag.GetValueObject(PropertyDesc, UTexture::StaticClass());
if (!Result.HasValue())
{
break;
}
MaterialInstance->SetTextureParameterValueByInfo(Parameter->MaterialParameter, Cast<UTexture>(Result.GetValue()));
break;
}
case EMetaHumanRuntimeMaterialParameterType::TextureCollection:
case EMetaHumanRuntimeMaterialParameterType::Font:
case EMetaHumanRuntimeMaterialParameterType::RuntimeVirtualTexture:
case EMetaHumanRuntimeMaterialParameterType::SparseVolumeTexture:
break;
}
}
}
}
bool ParametersToPropertyBag(
TNotNull<const UMaterialInstanceDynamic*> InMaterial,
const TArray<FMetaHumanMaterialParameter>& InMaterialParameters,
FInstancedPropertyBag& InOutPropertyBag)
{
int32 Count = 0;
for (const FMetaHumanMaterialParameter& MaterialParameter : InMaterialParameters)
{
FPropertyBagPropertyDesc PropertyDesc;
PropertyDesc.Name = MaterialParameter.InstanceParameterName;
#if WITH_EDITORONLY_DATA
for (const TPair<FName, FString>& ItPair : MaterialParameter.PropertyMetadata)
{
PropertyDesc.MetaData.Add(FPropertyBagPropertyDescMetaData(ItPair.Key, ItPair.Value));
}
#endif
// Get current parameter value and set property value
switch (MaterialParameter.ParameterType)
{
case EMetaHumanRuntimeMaterialParameterType::Toggle:
{
PropertyDesc.ValueType = EPropertyBagPropertyType::Bool;
FMaterialParameterMetadata MaterialValue;
if (InMaterial->GetParameterValue(EMaterialParameterType::Scalar, MaterialParameter.MaterialParameter, MaterialValue))
{
float Value = MaterialValue.Value.AsScalar();
verify(MaterialValue.Value.Type == EMaterialParameterType::Scalar);
InOutPropertyBag.AddProperties({ PropertyDesc }); // TODO: Better way to add desc?
InOutPropertyBag.SetValueBool(MaterialParameter.InstanceParameterName, Value > 0.0f);
}
}
break;
case EMetaHumanRuntimeMaterialParameterType::Scalar:
{
PropertyDesc.ValueType = EPropertyBagPropertyType::Float;
FMaterialParameterMetadata MaterialValue;
if (InMaterial->GetParameterValue(EMaterialParameterType::Scalar, MaterialParameter.MaterialParameter, MaterialValue))
{
float Value = MaterialValue.Value.AsScalar();
verify(MaterialValue.Value.Type == EMaterialParameterType::Scalar);
InOutPropertyBag.AddProperties({ PropertyDesc });
InOutPropertyBag.SetValueFloat(MaterialParameter.InstanceParameterName, Value);
}
}
break;
case EMetaHumanRuntimeMaterialParameterType::Vector:
{
PropertyDesc.ValueType = EPropertyBagPropertyType::Struct;
PropertyDesc.ValueTypeObject = TBaseStructure<FLinearColor>::Get();
FMaterialParameterMetadata MaterialValue;
if (InMaterial->GetParameterValue(EMaterialParameterType::Vector, MaterialParameter.MaterialParameter, MaterialValue))
{
FLinearColor Value = MaterialValue.Value.AsLinearColor();
verify(MaterialValue.Value.Type == EMaterialParameterType::Vector);
InOutPropertyBag.AddProperties({ PropertyDesc });
InOutPropertyBag.SetValueStruct(MaterialParameter.InstanceParameterName, Value);
}
}
break;
case EMetaHumanRuntimeMaterialParameterType::DoubleVector:
case EMetaHumanRuntimeMaterialParameterType::Texture:
{
PropertyDesc.ValueType = EPropertyBagPropertyType::Object;
PropertyDesc.ValueTypeObject = UTexture::StaticClass();
FMaterialParameterMetadata MaterialValue;
if (InMaterial->GetParameterValue(EMaterialParameterType::Texture, MaterialParameter.MaterialParameter, MaterialValue))
{
UTexture* Value = Cast<UTexture>(MaterialValue.Value.AsTextureObject());
verify(MaterialValue.Value.Type == EMaterialParameterType::Texture);
InOutPropertyBag.AddProperties({ PropertyDesc });
InOutPropertyBag.SetValueObject(MaterialParameter.InstanceParameterName, Value);
}
}
break;
case EMetaHumanRuntimeMaterialParameterType::TextureCollection:
case EMetaHumanRuntimeMaterialParameterType::Font:
case EMetaHumanRuntimeMaterialParameterType::RuntimeVirtualTexture:
case EMetaHumanRuntimeMaterialParameterType::SparseVolumeTexture:
break;
}
if (InOutPropertyBag.FindPropertyDescByName(MaterialParameter.InstanceParameterName))
{
Count++;
}
}
return Count > 0;
}
EMetaHumanRuntimeMaterialParameterType PropertyToParameterType(TNotNull<FProperty*> InProperty)
{
if (InProperty->IsA(FBoolProperty::StaticClass()))
{
return EMetaHumanRuntimeMaterialParameterType::Toggle;
}
else if (InProperty->IsA(FFloatProperty::StaticClass()))
{
return EMetaHumanRuntimeMaterialParameterType::Scalar;
}
else if (InProperty->IsA(FStructProperty::StaticClass()))
{
if (FStructProperty* StructProperty = CastField<FStructProperty>(InProperty))
{
if (StructProperty->Struct == TBaseStructure<FLinearColor>::Get()
|| StructProperty->Struct == TBaseStructure<FColor>::Get())
{
return EMetaHumanRuntimeMaterialParameterType::Vector;
}
}
}
else if (InProperty->IsA(FSoftObjectProperty::StaticClass()))
{
if (FSoftObjectProperty* SoftObjectProperty = CastField<FSoftObjectProperty>(InProperty))
{
if (SoftObjectProperty->PropertyClass->IsChildOf<UTexture>())
{
return EMetaHumanRuntimeMaterialParameterType::Texture;
}
}
}
else if (InProperty->IsA(FObjectProperty::StaticClass()))
{
if (FObjectProperty* ObjectProperty = CastField<FObjectProperty>(InProperty))
{
if (ObjectProperty->PropertyClass->IsChildOf<UTexture>())
{
return EMetaHumanRuntimeMaterialParameterType::Texture;
}
}
}
// TODO: Unsupported type
checkNoEntry();
return EMetaHumanRuntimeMaterialParameterType::Scalar;
}
#if WITH_EDITOR
TMap<FName, FString> CopyMetadataFromProperty(TNotNull<FProperty*> InProperty)
{
TMap<FName, FString> Result;
if (const TMap<FName, FString>* FoundMetaDataMap = InProperty->GetMetaDataMap())
{
Result = *FoundMetaDataMap;
Result.Remove(FName("ModuleRelativePath"));
}
return Result;
}
#endif
} // namespace UE::MetaHuman::MaterialUtils