// Copyright Epic Games, Inc. All Rights Reserved. #include "MaterialPropertyHelpers.h" #include "Misc/MessageDialog.h" #include "Misc/Guid.h" #include "UObject/UnrealType.h" #include "Layout/Margin.h" #include "Misc/Attribute.h" #include "Widgets/DeclarativeSyntaxSupport.h" #include "Widgets/SBoxPanel.h" #include "Widgets/Text/STextBlock.h" #include "Widgets/SToolTip.h" #include "EditorStyleSet.h" #include "Materials/MaterialInterface.h" #include "MaterialEditor/DEditorFontParameterValue.h" #include "MaterialEditor/DEditorMaterialLayersParameterValue.h" #include "MaterialEditor/DEditorRuntimeVirtualTextureParameterValue.h" #include "MaterialEditor/DEditorScalarParameterValue.h" #include "MaterialEditor/DEditorStaticComponentMaskParameterValue.h" #include "MaterialEditor/DEditorStaticSwitchParameterValue.h" #include "MaterialEditor/DEditorTextureParameterValue.h" #include "MaterialEditor/DEditorVectorParameterValue.h" #include "MaterialEditor/MaterialEditorInstanceConstant.h" #include "Materials/MaterialInstance.h" #include "Materials/MaterialExpressionParameter.h" #include "Materials/MaterialExpressionTextureSampleParameter.h" #include "Materials/MaterialExpressionFontSampleParameter.h" #include "Materials/MaterialExpressionMaterialAttributeLayers.h" #include "Materials/MaterialExpressionChannelMaskParameter.h" #include "EditorSupportDelegates.h" #include "DetailWidgetRow.h" #include "PropertyHandle.h" #include "IDetailPropertyRow.h" #include "DetailLayoutBuilder.h" #include "IDetailGroup.h" #include "DetailCategoryBuilder.h" #include "PropertyCustomizationHelpers.h" #include "ScopedTransaction.h" #include "Materials/MaterialInstanceConstant.h" #include "Materials/MaterialFunctionInstance.h" #include "Materials/MaterialFunction.h" #include "Materials/MaterialFunctionInterface.h" #include "Modules/ModuleManager.h" #include "AssetToolsModule.h" #include "Factories/MaterialInstanceConstantFactoryNew.h" #include "StaticParameterSet.h" #include "MaterialEditor/MaterialEditorPreviewParameters.h" #include "Factories/MaterialFunctionInstanceFactory.h" #include "SMaterialLayersFunctionsTree.h" #include "Materials/MaterialFunctionMaterialLayer.h" #include "Materials/MaterialFunctionMaterialLayerBlend.h" #include "Factories/MaterialFunctionMaterialLayerFactory.h" #include "Factories/MaterialFunctionMaterialLayerBlendFactory.h" #include "Curves/CurveLinearColorAtlas.h" #include "Curves/CurveLinearColor.h" #define LOCTEXT_NAMESPACE "MaterialPropertyHelper" FText FMaterialPropertyHelpers::LayerID = LOCTEXT("LayerID", "Layer Asset"); FText FMaterialPropertyHelpers::BlendID = LOCTEXT("BlendID", "Blend Asset"); FName FMaterialPropertyHelpers::LayerParamName = FName("Global Material Layers Parameter Values"); void SLayerHandle::Construct(const FArguments& InArgs) { OwningStack = InArgs._OwningStack; ChildSlot [ InArgs._Content.Widget ]; } FReply SLayerHandle::OnDragDetected(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { if (MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton)) { { TSharedPtr DragDropOp = CreateDragDropOperation(OwningStack.Pin()); if (DragDropOp.IsValid()) { OwningStack.Pin()->OnLayerDragDetected(); return FReply::Handled().BeginDragDrop(DragDropOp.ToSharedRef()); } } } return FReply::Unhandled(); } TSharedPtr SLayerHandle::CreateDragDropOperation(TSharedPtr InOwningStack) { TSharedPtr Operation = MakeShareable(new FLayerDragDropOp(InOwningStack)); return Operation; } EVisibility FMaterialPropertyHelpers::ShouldShowExpression(UDEditorParameterValue* Parameter, UMaterialEditorInstanceConstant* MaterialEditorInstance, FGetShowHiddenParameters ShowHiddenDelegate) { bool bShowHidden = true; ShowHiddenDelegate.ExecuteIfBound(bShowHidden); bool bIsCooked = false; if (MaterialEditorInstance->SourceInstance) { if (UMaterial* Material = MaterialEditorInstance->SourceInstance->GetMaterial()) { bIsCooked = Material->GetPackage()->bIsCookedForEditor; } } const bool bShouldShowExpression = bShowHidden || MaterialEditorInstance->VisibleExpressions.Contains(Parameter->ParameterInfo) || bIsCooked; if (MaterialEditorInstance->bShowOnlyOverrides) { return (IsOverriddenExpression(Parameter) && bShouldShowExpression) ? EVisibility::Visible : EVisibility::Collapsed; } return bShouldShowExpression ? EVisibility::Visible: EVisibility::Collapsed; } void FMaterialPropertyHelpers::OnMaterialLayerAssetChanged(const struct FAssetData& InAssetData, int32 Index, EMaterialParameterAssociation MaterialType, TSharedPtr InHandle, FMaterialLayersFunctions* InMaterialFunction) { const FScopedTransaction Transaction(LOCTEXT("SetLayerorBlendAsset", "Set Layer or Blend Asset")); InHandle->NotifyPreChange(); const FName FilterTag = FName(TEXT("MaterialFunctionUsage")); if (InAssetData.TagsAndValues.Contains(FilterTag) || InAssetData.AssetName == NAME_None) { UMaterialFunctionInterface* LayerFunction = Cast(InAssetData.GetAsset()); switch (MaterialType) { case EMaterialParameterAssociation::LayerParameter: if (InMaterialFunction->Layers[Index] != LayerFunction) { InMaterialFunction->Layers[Index] = LayerFunction; InMaterialFunction->UnlinkLayerFromParent(Index); } break; case EMaterialParameterAssociation::BlendParameter: if (InMaterialFunction->Blends[Index] != LayerFunction) { InMaterialFunction->Blends[Index] = LayerFunction; InMaterialFunction->UnlinkLayerFromParent(Index + 1); // Blend indices are offset by 1, no blend for base layer } break; default: break; } } InHandle->NotifyPostChange(EPropertyChangeType::ValueSet); } bool FMaterialPropertyHelpers::FilterLayerAssets(const struct FAssetData& InAssetData, FMaterialLayersFunctions* LayerFunction, EMaterialParameterAssociation MaterialType, int32 Index) { bool ShouldAssetBeFilteredOut = false; const FName FilterTag = FName(TEXT("MaterialFunctionUsage")); const FName BaseTag = FName(TEXT("Base")); FAssetDataTagMapSharedView::FFindTagResult MaterialFunctionUsage = InAssetData.TagsAndValues.FindTag(FilterTag); FName BaseClassName; FName InstanceClassName; FString CompareString; if (MaterialFunctionUsage.IsSet()) { FAssetDataTagMapSharedView::FFindTagResult Base = InAssetData.TagsAndValues.FindTag(BaseTag); FString BaseString; FString DiscardString; FString CleanString; if (Base.IsSet()) { BaseString = Base.GetValue(); BaseString.Split(".", &DiscardString, &CleanString); CleanString.Split("'", &CleanString, &DiscardString); } else { CleanString = InAssetData.AssetName.ToString(); } FString LeftPath; FString RightPath; bool bShouldFilter = false; switch (MaterialType) { case EMaterialParameterAssociation::LayerParameter: { CompareString = "MaterialLayer"; if (LayerFunction->Layers[Index] != nullptr) { RightPath = LayerFunction->Layers[Index]->GetBaseFunction()->GetFName().ToString(); if (RightPath.IsEmpty()) { RightPath = LayerFunction->Layers[Index]->GetFName().ToString(); } } bShouldFilter = LayerFunction->RestrictToLayerRelatives[Index]; BaseClassName = UMaterialFunctionMaterialLayer::StaticClass()->GetFName(); InstanceClassName = UMaterialFunctionMaterialLayerInstance::StaticClass()->GetFName(); } break; case EMaterialParameterAssociation::BlendParameter: { CompareString = "MaterialLayerBlend"; if (LayerFunction->Blends[Index] != nullptr) { RightPath = LayerFunction->Blends[Index]->GetBaseFunction()->GetFName().ToString(); if (RightPath.IsEmpty()) { RightPath = LayerFunction->Blends[Index]->GetFName().ToString(); } } bShouldFilter = LayerFunction->RestrictToBlendRelatives[Index]; BaseClassName = UMaterialFunctionMaterialLayerBlend::StaticClass()->GetFName(); InstanceClassName = UMaterialFunctionMaterialLayerBlendInstance::StaticClass()->GetFName(); } break; default: break; } if (MaterialFunctionUsage.GetValue() != CompareString) { ShouldAssetBeFilteredOut = true; } else { bool bSameBase = CleanString == RightPath; if (!RightPath.IsEmpty() && !bSameBase && bShouldFilter) { ShouldAssetBeFilteredOut = true; } } } else { ShouldAssetBeFilteredOut = true; } return ShouldAssetBeFilteredOut; } FReply FMaterialPropertyHelpers::OnClickedSaveNewMaterialInstance(UMaterialInterface* Parent, UObject* EditorObject) { const FString DefaultSuffix = TEXT("_Inst"); TArray ParameterGroups; UMaterialEditorInstanceConstant* MaterialInstanceEditor = Cast(EditorObject); if (MaterialInstanceEditor) { ParameterGroups = MaterialInstanceEditor->ParameterGroups; } UMaterialEditorPreviewParameters* MaterialEditor = Cast(EditorObject); if (MaterialEditor) { ParameterGroups = MaterialEditor->ParameterGroups; } if (!MaterialEditor && !MaterialInstanceEditor) { return FReply::Unhandled(); } if (Parent) { // Create an appropriate and unique name FString Name; FString PackageName; FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked("AssetTools"); AssetToolsModule.Get().CreateUniqueAssetName(Parent->GetOutermost()->GetName(), DefaultSuffix, PackageName, Name); UMaterialInstanceConstantFactoryNew* Factory = NewObject(); Factory->InitialParent = Parent; UObject* Child = AssetToolsModule.Get().CreateAssetWithDialog(Name, FPackageName::GetLongPackagePath(PackageName), UMaterialInstanceConstant::StaticClass(), Factory); UMaterialInstanceConstant* ChildInstance = Cast(Child); CopyMaterialToInstance(ChildInstance, ParameterGroups); } return FReply::Handled(); } void FMaterialPropertyHelpers::CopyMaterialToInstance(UMaterialInstanceConstant* ChildInstance, TArray &ParameterGroups) { if (ChildInstance) { if (ChildInstance->IsTemplate(RF_ClassDefaultObject) == false) { ChildInstance->MarkPackageDirty(); ChildInstance->ClearParameterValuesEditorOnly(); //propagate changes to the base material so the instance will be updated if it has a static permutation resource FStaticParameterSet NewStaticParameters; for (int32 GroupIdx = 0; GroupIdx < ParameterGroups.Num(); GroupIdx++) { FEditorParameterGroup& Group = ParameterGroups[GroupIdx]; for (int32 ParameterIdx = 0; ParameterIdx < Group.Parameters.Num(); ParameterIdx++) { if (Group.Parameters[ParameterIdx] == NULL) { continue; } UDEditorScalarParameterValue* ScalarParameterValue = Cast(Group.Parameters[ParameterIdx]); if (ScalarParameterValue) { if (ScalarParameterValue->bOverride) { ChildInstance->SetScalarParameterValueEditorOnly(ScalarParameterValue->ParameterInfo, ScalarParameterValue->ParameterValue); continue; } } UDEditorFontParameterValue* FontParameterValue = Cast(Group.Parameters[ParameterIdx]); if (FontParameterValue) { if (FontParameterValue->bOverride) { ChildInstance->SetFontParameterValueEditorOnly(FontParameterValue->ParameterInfo, FontParameterValue->ParameterValue.FontValue, FontParameterValue->ParameterValue.FontPage); continue; } } UDEditorTextureParameterValue* TextureParameterValue = Cast(Group.Parameters[ParameterIdx]); if (TextureParameterValue) { if (TextureParameterValue->bOverride) { ChildInstance->SetTextureParameterValueEditorOnly(TextureParameterValue->ParameterInfo, TextureParameterValue->ParameterValue); continue; } } UDEditorRuntimeVirtualTextureParameterValue* RuntimeVirtualTextureParameterValue = Cast(Group.Parameters[ParameterIdx]); if (RuntimeVirtualTextureParameterValue) { if (RuntimeVirtualTextureParameterValue->bOverride) { ChildInstance->SetRuntimeVirtualTextureParameterValueEditorOnly(RuntimeVirtualTextureParameterValue->ParameterInfo, RuntimeVirtualTextureParameterValue->ParameterValue); continue; } } UDEditorVectorParameterValue* VectorParameterValue = Cast(Group.Parameters[ParameterIdx]); if (VectorParameterValue) { if (VectorParameterValue->bOverride) { ChildInstance->SetVectorParameterValueEditorOnly(VectorParameterValue->ParameterInfo, VectorParameterValue->ParameterValue); continue; } } UDEditorMaterialLayersParameterValue* LayersParameterValue = Cast(Group.Parameters[ParameterIdx]); if (LayersParameterValue) { FMaterialLayersFunctions LayerValue = LayersParameterValue->ParameterValue; FGuid ExpressionIdValue = LayersParameterValue->ExpressionId; if (LayersParameterValue->bOverride) { FStaticMaterialLayersParameter* NewParameter = new(NewStaticParameters.MaterialLayersParameters) FStaticMaterialLayersParameter(LayersParameterValue->ParameterInfo, LayerValue, LayersParameterValue->bOverride, ExpressionIdValue); } } UDEditorStaticSwitchParameterValue* StaticSwitchParameterValue = Cast(Group.Parameters[ParameterIdx]); if (StaticSwitchParameterValue) { bool SwitchValue = StaticSwitchParameterValue->ParameterValue; FGuid ExpressionIdValue = StaticSwitchParameterValue->ExpressionId; if (StaticSwitchParameterValue->bOverride) { FStaticSwitchParameter* NewParameter = new(NewStaticParameters.StaticSwitchParameters) FStaticSwitchParameter(StaticSwitchParameterValue->ParameterInfo, SwitchValue, StaticSwitchParameterValue->bOverride, ExpressionIdValue); } } // static component mask UDEditorStaticComponentMaskParameterValue* StaticComponentMaskParameterValue = Cast(Group.Parameters[ParameterIdx]); if (StaticComponentMaskParameterValue) { bool MaskR = StaticComponentMaskParameterValue->ParameterValue.R; bool MaskG = StaticComponentMaskParameterValue->ParameterValue.G; bool MaskB = StaticComponentMaskParameterValue->ParameterValue.B; bool MaskA = StaticComponentMaskParameterValue->ParameterValue.A; FGuid ExpressionIdValue = StaticComponentMaskParameterValue->ExpressionId; if (StaticComponentMaskParameterValue->bOverride) { FStaticComponentMaskParameter* NewParameter = new(NewStaticParameters.StaticComponentMaskParameters) FStaticComponentMaskParameter(StaticComponentMaskParameterValue->ParameterInfo, MaskR, MaskG, MaskB, MaskA, StaticComponentMaskParameterValue->bOverride, ExpressionIdValue); } } } } ChildInstance->UpdateStaticPermutation(NewStaticParameters); } } } void FMaterialPropertyHelpers::TransitionAndCopyParameters(UMaterialInstanceConstant* ChildInstance, TArray &ParameterGroups, bool bForceCopy) { if (ChildInstance) { if (ChildInstance->IsTemplate(RF_ClassDefaultObject) == false) { ChildInstance->MarkPackageDirty(); ChildInstance->ClearParameterValuesEditorOnly(); //propagate changes to the base material so the instance will be updated if it has a static permutation resource FStaticParameterSet NewStaticParameters; for (int32 GroupIdx = 0; GroupIdx < ParameterGroups.Num(); GroupIdx++) { FEditorParameterGroup& Group = ParameterGroups[GroupIdx]; for (int32 ParameterIdx = 0; ParameterIdx < Group.Parameters.Num(); ParameterIdx++) { if (Group.Parameters[ParameterIdx] == NULL) { continue; } UDEditorScalarParameterValue* ScalarParameterValue = Cast(Group.Parameters[ParameterIdx]); if (ScalarParameterValue) { if (ScalarParameterValue->bOverride || bForceCopy) { FMaterialParameterInfo TransitionedScalarInfo = FMaterialParameterInfo(); TransitionedScalarInfo.Name = ScalarParameterValue->ParameterInfo.Name; ChildInstance->SetScalarParameterValueEditorOnly(TransitionedScalarInfo, ScalarParameterValue->ParameterValue); continue; } } UDEditorFontParameterValue* FontParameterValue = Cast(Group.Parameters[ParameterIdx]); if (FontParameterValue) { if (FontParameterValue->bOverride || bForceCopy) { FMaterialParameterInfo TransitionedFontInfo = FMaterialParameterInfo(); TransitionedFontInfo.Name = FontParameterValue->ParameterInfo.Name; ChildInstance->SetFontParameterValueEditorOnly(TransitionedFontInfo, FontParameterValue->ParameterValue.FontValue, FontParameterValue->ParameterValue.FontPage); continue; } } UDEditorTextureParameterValue* TextureParameterValue = Cast(Group.Parameters[ParameterIdx]); if (TextureParameterValue) { if (TextureParameterValue->bOverride || bForceCopy) { FMaterialParameterInfo TransitionedTextureInfo = FMaterialParameterInfo(); TransitionedTextureInfo.Name = TextureParameterValue->ParameterInfo.Name; ChildInstance->SetTextureParameterValueEditorOnly(TransitionedTextureInfo, TextureParameterValue->ParameterValue); continue; } } UDEditorRuntimeVirtualTextureParameterValue* RVTParameterValue = Cast(Group.Parameters[ParameterIdx]); if (RVTParameterValue) { if (RVTParameterValue->bOverride || bForceCopy) { FMaterialParameterInfo TransitionedTextureInfo = FMaterialParameterInfo(); TransitionedTextureInfo.Name = RVTParameterValue->ParameterInfo.Name; ChildInstance->SetRuntimeVirtualTextureParameterValueEditorOnly(TransitionedTextureInfo, RVTParameterValue->ParameterValue); continue; } } UDEditorVectorParameterValue* VectorParameterValue = Cast(Group.Parameters[ParameterIdx]); if (VectorParameterValue) { if (VectorParameterValue->bOverride || bForceCopy) { FMaterialParameterInfo TransitionedVectorInfo = FMaterialParameterInfo(); TransitionedVectorInfo.Name = VectorParameterValue->ParameterInfo.Name; ChildInstance->SetVectorParameterValueEditorOnly(TransitionedVectorInfo, VectorParameterValue->ParameterValue); continue; } } UDEditorStaticSwitchParameterValue* StaticSwitchParameterValue = Cast(Group.Parameters[ParameterIdx]); if (StaticSwitchParameterValue) { bool SwitchValue = StaticSwitchParameterValue->ParameterValue; FGuid ExpressionIdValue = StaticSwitchParameterValue->ExpressionId; if (StaticSwitchParameterValue->bOverride || bForceCopy) { FMaterialParameterInfo TransitionedSwitchInfo = FMaterialParameterInfo(); TransitionedSwitchInfo.Name = StaticSwitchParameterValue->ParameterInfo.Name; FStaticSwitchParameter* NewParameter = new(NewStaticParameters.StaticSwitchParameters) FStaticSwitchParameter(TransitionedSwitchInfo, SwitchValue, StaticSwitchParameterValue->bOverride, ExpressionIdValue); } } // static component mask UDEditorStaticComponentMaskParameterValue* StaticComponentMaskParameterValue = Cast(Group.Parameters[ParameterIdx]); if (StaticComponentMaskParameterValue) { bool MaskR = StaticComponentMaskParameterValue->ParameterValue.R; bool MaskG = StaticComponentMaskParameterValue->ParameterValue.G; bool MaskB = StaticComponentMaskParameterValue->ParameterValue.B; bool MaskA = StaticComponentMaskParameterValue->ParameterValue.A; FGuid ExpressionIdValue = StaticComponentMaskParameterValue->ExpressionId; if (StaticComponentMaskParameterValue->bOverride || bForceCopy) { FMaterialParameterInfo TransitionedMaskInfo = FMaterialParameterInfo(); TransitionedMaskInfo.Name = StaticComponentMaskParameterValue->ParameterInfo.Name; FStaticComponentMaskParameter* NewParameter = new(NewStaticParameters.StaticComponentMaskParameters) FStaticComponentMaskParameter(TransitionedMaskInfo, MaskR, MaskG, MaskB, MaskA, StaticComponentMaskParameterValue->bOverride, ExpressionIdValue); } } } } ChildInstance->UpdateStaticPermutation(NewStaticParameters); } } } FReply FMaterialPropertyHelpers::OnClickedSaveNewFunctionInstance(class UMaterialFunctionInterface* Object, class UMaterialInterface* PreviewMaterial, UObject* EditorObject) { const FString DefaultSuffix = TEXT("_Inst"); TArray ParameterGroups; UMaterialEditorInstanceConstant* MaterialInstanceEditor = Cast(EditorObject); UMaterialInterface* FunctionPreviewMaterial = nullptr; if (MaterialInstanceEditor) { ParameterGroups = MaterialInstanceEditor->ParameterGroups; FunctionPreviewMaterial = MaterialInstanceEditor->SourceInstance; } UMaterialEditorPreviewParameters* MaterialEditor = Cast(EditorObject); if (MaterialEditor) { ParameterGroups = MaterialEditor->ParameterGroups; FunctionPreviewMaterial = PreviewMaterial; } if (!MaterialEditor && !MaterialInstanceEditor) { return FReply::Unhandled(); } if (Object) { UMaterial* EditedMaterial = Cast(FunctionPreviewMaterial); if (EditedMaterial) { UMaterialInstanceConstant* ProxyMaterial = NewObject(GetTransientPackage(), NAME_None, RF_Transactional); ProxyMaterial->SetParentEditorOnly(EditedMaterial); ProxyMaterial->PreEditChange(NULL); ProxyMaterial->PostEditChange(); CopyMaterialToInstance(ProxyMaterial, ParameterGroups); FunctionPreviewMaterial = ProxyMaterial; } // Create an appropriate and unique name FString Name; FString PackageName; FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked("AssetTools"); AssetToolsModule.Get().CreateUniqueAssetName(Object->GetOutermost()->GetName(), DefaultSuffix, PackageName, Name); UObject* Child; if (Object->GetMaterialFunctionUsage() == EMaterialFunctionUsage::MaterialLayer) { UMaterialFunctionMaterialLayerInstanceFactory* LayerFactory = NewObject(); LayerFactory->InitialParent = Object; Child = AssetToolsModule.Get().CreateAssetWithDialog(Name, FPackageName::GetLongPackagePath(PackageName), UMaterialFunctionMaterialLayerInstance::StaticClass(), LayerFactory); } else if (Object->GetMaterialFunctionUsage() == EMaterialFunctionUsage::MaterialLayerBlend) { UMaterialFunctionMaterialLayerBlendInstanceFactory* BlendFactory = NewObject(); BlendFactory->InitialParent = Object; Child = AssetToolsModule.Get().CreateAssetWithDialog(Name, FPackageName::GetLongPackagePath(PackageName), UMaterialFunctionMaterialLayerBlendInstance::StaticClass(), BlendFactory); } else { UMaterialFunctionInstanceFactory* Factory = NewObject(); Factory->InitialParent = Object; Child = AssetToolsModule.Get().CreateAssetWithDialog(Name, FPackageName::GetLongPackagePath(PackageName), UMaterialFunctionInstance::StaticClass(), Factory); } UMaterialFunctionInstance* ChildInstance = Cast(Child); if (ChildInstance) { if (ChildInstance->IsTemplate(RF_ClassDefaultObject) == false) { ChildInstance->MarkPackageDirty(); ChildInstance->SetParent(Object); UMaterialInstance* EditedInstance = Cast(FunctionPreviewMaterial); if (EditedInstance) { ChildInstance->ScalarParameterValues = EditedInstance->ScalarParameterValues; ChildInstance->VectorParameterValues = EditedInstance->VectorParameterValues; ChildInstance->TextureParameterValues = EditedInstance->TextureParameterValues; ChildInstance->RuntimeVirtualTextureParameterValues = EditedInstance->RuntimeVirtualTextureParameterValues; ChildInstance->FontParameterValues = EditedInstance->FontParameterValues; const FStaticParameterSet& StaticParameters = EditedInstance->GetStaticParameters(); ChildInstance->StaticSwitchParameterValues = StaticParameters.StaticSwitchParameters; ChildInstance->StaticComponentMaskParameterValues = StaticParameters.StaticComponentMaskParameters; } } } } return FReply::Handled(); } FReply FMaterialPropertyHelpers::OnClickedSaveNewLayerInstance(class UMaterialFunctionInterface* Object, TSharedPtr InSortedData) { const FString DefaultSuffix = TEXT("_Inst"); TArray ParameterGroups; UMaterialInterface* FunctionPreviewMaterial = nullptr; if (Object) { FunctionPreviewMaterial = Object->GetPreviewMaterial(); } for (TSharedPtr Group : InSortedData->Children) { FEditorParameterGroup DuplicatedGroup = FEditorParameterGroup(); DuplicatedGroup.GroupAssociation = Group->Group.GroupAssociation; DuplicatedGroup.GroupName = Group->Group.GroupName; DuplicatedGroup.GroupSortPriority = Group->Group.GroupSortPriority; for (UDEditorParameterValue* Parameter : Group->Group.Parameters) { if (Parameter->ParameterInfo.Index == InSortedData->ParameterInfo.Index) { DuplicatedGroup.Parameters.Add(Parameter); } } ParameterGroups.Add(DuplicatedGroup); } if (Object) { UMaterialInterface* EditedMaterial = FunctionPreviewMaterial; if (EditedMaterial) { UMaterialInstanceConstant* ProxyMaterial = NewObject(GetTransientPackage(), NAME_None, RF_Transactional); ProxyMaterial->SetParentEditorOnly(EditedMaterial); ProxyMaterial->PreEditChange(NULL); ProxyMaterial->PostEditChange(); TransitionAndCopyParameters(ProxyMaterial, ParameterGroups); FunctionPreviewMaterial = ProxyMaterial; } // Create an appropriate and unique name FString Name; FString PackageName; FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked("AssetTools"); AssetToolsModule.Get().CreateUniqueAssetName(Object->GetOutermost()->GetName(), DefaultSuffix, PackageName, Name); UObject* Child; if (Object->GetMaterialFunctionUsage() == EMaterialFunctionUsage::MaterialLayer) { UMaterialFunctionMaterialLayerInstanceFactory* LayerFactory = NewObject(); LayerFactory->InitialParent = Object; Child = AssetToolsModule.Get().CreateAssetWithDialog(Name, FPackageName::GetLongPackagePath(PackageName), UMaterialFunctionMaterialLayerInstance::StaticClass(), LayerFactory); } else if (Object->GetMaterialFunctionUsage() == EMaterialFunctionUsage::MaterialLayerBlend) { UMaterialFunctionMaterialLayerBlendInstanceFactory* BlendFactory = NewObject(); BlendFactory->InitialParent = Object; Child = AssetToolsModule.Get().CreateAssetWithDialog(Name, FPackageName::GetLongPackagePath(PackageName), UMaterialFunctionMaterialLayerBlendInstance::StaticClass(), BlendFactory); } else { UMaterialFunctionInstanceFactory* Factory = NewObject(); Factory->InitialParent = Object; Child = AssetToolsModule.Get().CreateAssetWithDialog(Name, FPackageName::GetLongPackagePath(PackageName), UMaterialFunctionInstance::StaticClass(), Factory); } UMaterialFunctionInstance* ChildInstance = Cast(Child); if (ChildInstance) { if (ChildInstance->IsTemplate(RF_ClassDefaultObject) == false) { ChildInstance->MarkPackageDirty(); ChildInstance->SetParent(Object); UMaterialInstance* EditedInstance = Cast(FunctionPreviewMaterial); if (EditedInstance) { ChildInstance->ScalarParameterValues = EditedInstance->ScalarParameterValues; ChildInstance->VectorParameterValues = EditedInstance->VectorParameterValues; ChildInstance->TextureParameterValues = EditedInstance->TextureParameterValues; ChildInstance->RuntimeVirtualTextureParameterValues = EditedInstance->RuntimeVirtualTextureParameterValues; ChildInstance->FontParameterValues = EditedInstance->FontParameterValues; const FStaticParameterSet& StaticParameters = EditedInstance->GetStaticParameters(); ChildInstance->StaticSwitchParameterValues = StaticParameters.StaticSwitchParameters; ChildInstance->StaticComponentMaskParameterValues = StaticParameters.StaticComponentMaskParameters; } } } } return FReply::Handled(); } bool FMaterialPropertyHelpers::IsOverriddenExpression(UDEditorParameterValue* Parameter) { return Parameter->bOverride != 0; } ECheckBoxState FMaterialPropertyHelpers::IsOverriddenExpressionCheckbox(UDEditorParameterValue* Parameter) { return IsOverriddenExpression(Parameter) ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; } void FMaterialPropertyHelpers::OnOverrideParameter(bool NewValue, class UDEditorParameterValue* Parameter, UMaterialEditorInstanceConstant* MaterialEditorInstance) { const FScopedTransaction Transaction( LOCTEXT( "OverrideParameter", "Override Parameter" ) ); Parameter->Modify(); Parameter->bOverride = NewValue; // Fire off a dummy event to the material editor instance, so it knows to update the material, then refresh the viewports. FPropertyChangedEvent OverrideEvent(NULL); MaterialEditorInstance->PostEditChangeProperty( OverrideEvent ); FEditorSupportDelegates::RedrawAllViewports.Broadcast(); FEditorSupportDelegates::UpdateUI.Broadcast(); } FText FMaterialPropertyHelpers::GetParameterExpressionDescription(UDEditorParameterValue* Parameter, UObject* MaterialEditorInstance) { if (Parameter->ExpressionId.IsValid()) { UMaterial* BaseMaterial = nullptr; UMaterialEditorInstanceConstant* MaterialInstanceEditor = Cast(MaterialEditorInstance); if (MaterialInstanceEditor) { BaseMaterial = MaterialInstanceEditor->SourceInstance->GetMaterial(); } UMaterialEditorPreviewParameters* MaterialEditor = Cast(MaterialEditorInstance); if (MaterialEditor) { BaseMaterial = MaterialEditor->OriginalMaterial; } // TODO: This needs to support functions added by SourceInstance layers if (BaseMaterial) { UMaterialExpression* MaterialExpression = BaseMaterial->FindExpressionByGUID(Parameter->ExpressionId); if (MaterialExpression) { return FText::FromString(MaterialExpression->Desc); } } } return FText::GetEmpty(); } FText FMaterialPropertyHelpers::GetParameterTooltip(UDEditorParameterValue* Parameter, UObject* MaterialEditorInstance) { UMaterial* BaseMaterial = nullptr; UMaterialEditorInstanceConstant* MaterialInstanceEditor = Cast(MaterialEditorInstance); if (MaterialInstanceEditor) { BaseMaterial = MaterialInstanceEditor->SourceInstance->GetMaterial(); } UMaterialEditorPreviewParameters* MaterialEditor = Cast(MaterialEditorInstance); if (MaterialEditor) { BaseMaterial = MaterialEditor->OriginalMaterial; } // TODO: This needs to support functions added by SourceInstance layers if (BaseMaterial) { UMaterialExpression* MaterialExpression = BaseMaterial->FindExpressionByGUID(Parameter->ExpressionId); if (MaterialExpression) { const FText AssetPath = FText::FromString(MaterialExpression->GetAssetPathName()); FText TooltipText; if (!MaterialExpression->Desc.IsEmpty()) { TooltipText = FText::Format(LOCTEXT("ParameterInfoDescAndLocation", "{0} \nFound in: {1}"), FText::FromString(MaterialExpression->Desc), AssetPath); } else { TooltipText = FText::Format(LOCTEXT("ParameterInfoLocationOnly", "Found in: {0}"), AssetPath); } return TooltipText; } } return FText::GetEmpty(); } void FMaterialPropertyHelpers::ResetToDefault(class UDEditorParameterValue* Parameter, UMaterialEditorInstanceConstant* MaterialEditorInstance) { const FScopedTransaction Transaction( LOCTEXT( "ResetToDefault", "Reset To Default" ) ); Parameter->Modify(); const FMaterialParameterInfo& ParameterInfo = Parameter->ParameterInfo; UDEditorScalarParameterValue* ScalarParam = Cast(Parameter); UDEditorVectorParameterValue* VectorParam = Cast(Parameter); UDEditorTextureParameterValue* TextureParam = Cast(Parameter); UDEditorRuntimeVirtualTextureParameterValue* RuntimeVirtualTextureParam = Cast(Parameter); UDEditorFontParameterValue* FontParam = Cast(Parameter); UDEditorStaticSwitchParameterValue* SwitchParam = Cast(Parameter); UDEditorStaticComponentMaskParameterValue* CompMaskParam = Cast(Parameter); UDEditorMaterialLayersParameterValue* LayersParam = Cast(Parameter); if (ScalarParam) { float OutValue; if (MaterialEditorInstance->SourceInstance->GetScalarParameterDefaultValue(ParameterInfo, OutValue)) { ScalarParam->ParameterValue = OutValue; MaterialEditorInstance->CopyToSourceInstance(); } } else if (VectorParam) { FLinearColor OutValue; if (MaterialEditorInstance->SourceInstance->GetVectorParameterDefaultValue(ParameterInfo, OutValue)) { VectorParam->ParameterValue = OutValue; MaterialEditorInstance->CopyToSourceInstance(); } } else if (TextureParam) { UTexture* OutValue; if (MaterialEditorInstance->SourceInstance->GetTextureParameterDefaultValue(ParameterInfo, OutValue)) { TextureParam->ParameterValue = OutValue; MaterialEditorInstance->CopyToSourceInstance(); } } else if (RuntimeVirtualTextureParam) { URuntimeVirtualTexture* OutValue; if (MaterialEditorInstance->SourceInstance->GetRuntimeVirtualTextureParameterDefaultValue(ParameterInfo, OutValue)) { RuntimeVirtualTextureParam->ParameterValue = OutValue; MaterialEditorInstance->CopyToSourceInstance(); } } else if (FontParam) { UFont* OutFontValue; int32 OutFontPage; if (MaterialEditorInstance->SourceInstance->GetFontParameterDefaultValue(ParameterInfo, OutFontValue, OutFontPage)) { FontParam->ParameterValue.FontValue = OutFontValue; FontParam->ParameterValue.FontPage = OutFontPage; MaterialEditorInstance->CopyToSourceInstance(); } } else if (SwitchParam) { bool OutValue; FGuid TempGuid(0,0,0,0); if (MaterialEditorInstance->SourceInstance->GetStaticSwitchParameterDefaultValue(ParameterInfo, OutValue, TempGuid)) { SwitchParam->ParameterValue = OutValue; MaterialEditorInstance->CopyToSourceInstance(); } } else if (CompMaskParam) { bool OutValue[4]; FGuid TempGuid(0,0,0,0); if (MaterialEditorInstance->SourceInstance->GetStaticComponentMaskParameterDefaultValue(ParameterInfo, OutValue[0], OutValue[1], OutValue[2], OutValue[3], TempGuid)) { CompMaskParam->ParameterValue.R = OutValue[0]; CompMaskParam->ParameterValue.G = OutValue[1]; CompMaskParam->ParameterValue.B = OutValue[2]; CompMaskParam->ParameterValue.A = OutValue[3]; MaterialEditorInstance->CopyToSourceInstance(); } } } void FMaterialPropertyHelpers::ResetLayerAssetToDefault(UDEditorParameterValue* InParameter, TEnumAsByte InAssociation, int32 Index, UMaterialEditorInstanceConstant* MaterialEditorInstance) { const FScopedTransaction Transaction(LOCTEXT("ResetToDefault", "Reset To Default")); InParameter->Modify(); const FMaterialParameterInfo& ParameterInfo = InParameter->ParameterInfo; UDEditorMaterialLayersParameterValue* LayersParam = Cast(InParameter); if (LayersParam) { FMaterialLayersFunctions LayersValue; FGuid TempGuid(0, 0, 0, 0); if (MaterialEditorInstance->Parent->GetMaterialLayersParameterValue(ParameterInfo, LayersValue, TempGuid)) { FMaterialLayersFunctions StoredValue = LayersParam->ParameterValue; if (InAssociation == EMaterialParameterAssociation::BlendParameter) { if (Index < LayersValue.Blends.Num()) { StoredValue.Blends[Index] = LayersValue.Blends[Index]; } else { StoredValue.Blends[Index] = nullptr; MaterialEditorInstance->StoredBlendPreviews[Index] = nullptr; } } else if (InAssociation == EMaterialParameterAssociation::LayerParameter) { if (Index < LayersValue.Layers.Num()) { StoredValue.Layers[Index] = LayersValue.Layers[Index]; } else { StoredValue.Layers[Index] = nullptr; MaterialEditorInstance->StoredLayerPreviews[Index] = nullptr; } } LayersParam->ParameterValue = StoredValue; } } FPropertyChangedEvent OverrideEvent(NULL); MaterialEditorInstance->PostEditChangeProperty(OverrideEvent); FEditorSupportDelegates::RedrawAllViewports.Broadcast(); FEditorSupportDelegates::UpdateUI.Broadcast(); } bool FMaterialPropertyHelpers::ShouldLayerAssetShowResetToDefault(TSharedPtr InParameterData, UMaterialInterface* InMaterial) { if (!InParameterData->Parameter) { return false; } TArray StoredAssets; TArray ParentAssets; const FMaterialParameterInfo& ParameterInfo = InParameterData->Parameter->ParameterInfo; int32 Index = InParameterData->ParameterInfo.Index; UDEditorMaterialLayersParameterValue* LayersParam = Cast(InParameterData->Parameter); if (LayersParam) { FMaterialLayersFunctions LayersValue; FGuid TempGuid(0, 0, 0, 0); if (InMaterial->GetMaterialLayersParameterValue(ParameterInfo, LayersValue, TempGuid)) { FMaterialLayersFunctions StoredValue = LayersParam->ParameterValue; if (InParameterData->ParameterInfo.Association == EMaterialParameterAssociation::BlendParameter) { StoredAssets = StoredValue.Blends; ParentAssets = LayersValue.Blends; } else if (InParameterData->ParameterInfo.Association == EMaterialParameterAssociation::LayerParameter) { StoredAssets = StoredValue.Layers; ParentAssets = LayersValue.Layers; } // Compare to the parent MaterialFunctionInterface array if (Index < ParentAssets.Num()) { if (StoredAssets[Index] == ParentAssets[Index]) { return false; } else { return true; } } else if (StoredAssets[Index] != nullptr) { return true; } } } return false; } bool FMaterialPropertyHelpers::ShouldShowResetToDefault(UDEditorParameterValue* InParameter, UMaterialEditorInstanceConstant* MaterialEditorInstance) { const FMaterialParameterInfo& ParameterInfo = InParameter->ParameterInfo; UDEditorFontParameterValue* FontParam = Cast(InParameter); UDEditorScalarParameterValue* ScalarParam = Cast(InParameter); UDEditorStaticComponentMaskParameterValue* CompMaskParam = Cast(InParameter); UDEditorStaticSwitchParameterValue* SwitchParam = Cast(InParameter); UDEditorTextureParameterValue* TextureParam = Cast(InParameter); UDEditorRuntimeVirtualTextureParameterValue* RuntimeVirtualTextureParam = Cast(InParameter); UDEditorVectorParameterValue* VectorParam = Cast(InParameter); if (ScalarParam) { float OutValue; if (MaterialEditorInstance->SourceInstance->GetScalarParameterDefaultValue(ParameterInfo, OutValue)) { if (ScalarParam->ParameterValue != OutValue) { return true; } } } else if (FontParam) { UFont* OutFontValue; int32 OutFontPage; if (MaterialEditorInstance->SourceInstance->GetFontParameterDefaultValue(ParameterInfo, OutFontValue, OutFontPage)) { if (FontParam->ParameterValue.FontValue != OutFontValue || FontParam->ParameterValue.FontPage != OutFontPage) { return true; } } } else if (TextureParam) { UTexture* OutValue; if (MaterialEditorInstance->SourceInstance->GetTextureParameterDefaultValue(ParameterInfo, OutValue)) { if (TextureParam->ParameterValue != OutValue) { return true; } } } else if (RuntimeVirtualTextureParam) { URuntimeVirtualTexture* OutValue; if (MaterialEditorInstance->SourceInstance->GetRuntimeVirtualTextureParameterDefaultValue(ParameterInfo, OutValue)) { if (RuntimeVirtualTextureParam->ParameterValue != OutValue) { return true; } } } else if (VectorParam) { FLinearColor OutValue; if (MaterialEditorInstance->SourceInstance->GetVectorParameterDefaultValue(ParameterInfo, OutValue)) { if (VectorParam->ParameterValue != OutValue) { return true; } } } else if (SwitchParam) { bool OutValue; FGuid TempGuid(0, 0, 0, 0); if (MaterialEditorInstance->SourceInstance->GetStaticSwitchParameterDefaultValue(ParameterInfo, OutValue, TempGuid)) { if (SwitchParam->ParameterValue != OutValue) { return true; } } } else if (CompMaskParam) { bool OutValue[4]; FGuid TempGuid(0, 0, 0, 0); if (MaterialEditorInstance->SourceInstance->GetStaticComponentMaskParameterDefaultValue(ParameterInfo, OutValue[0], OutValue[1], OutValue[2], OutValue[3], TempGuid)) { if (CompMaskParam->ParameterValue.R != OutValue[0] || CompMaskParam->ParameterValue.G != OutValue[1] || CompMaskParam->ParameterValue.B != OutValue[2] || CompMaskParam->ParameterValue.A != OutValue[3]) { return true; } } } return false; } FEditorParameterGroup& FMaterialPropertyHelpers::GetParameterGroup(UMaterial* InMaterial, FName& ParameterGroup, TArray& ParameterGroups) { if (ParameterGroup == TEXT("")) { ParameterGroup = TEXT("None"); } for (int32 i = 0; i < ParameterGroups.Num(); i++) { FEditorParameterGroup& Group = ParameterGroups[i]; if (Group.GroupName == ParameterGroup) { return Group; } } int32 ind = ParameterGroups.AddZeroed(1); FEditorParameterGroup& Group = ParameterGroups[ind]; Group.GroupName = ParameterGroup; UMaterial* ParentMaterial = InMaterial; int32 NewSortPriority; if (ParentMaterial->GetGroupSortPriority(ParameterGroup.ToString(), NewSortPriority)) { Group.GroupSortPriority = NewSortPriority; } else { Group.GroupSortPriority = 0; } Group.GroupAssociation = EMaterialParameterAssociation::GlobalParameter; return Group; } void FMaterialPropertyHelpers::GetVectorChannelMaskComboBoxStrings(TArray>& OutComboBoxStrings, TArray>& OutToolTips, TArray& OutRestrictedItems) { const UEnum* ChannelEnum = StaticEnum(); check(ChannelEnum); // Add RGBA string options (Note: Exclude the "::Max" entry) const int32 NumEnums = ChannelEnum->NumEnums() - 1; for (int32 Entry = 0; Entry < NumEnums; ++Entry) { FText EnumName = ChannelEnum->GetDisplayNameTextByIndex(Entry); OutComboBoxStrings.Add(MakeShared(EnumName.ToString())); OutToolTips.Add(SNew(SToolTip).Text(EnumName)); OutRestrictedItems.Add(false); } } FString FMaterialPropertyHelpers::GetVectorChannelMaskValue(UDEditorParameterValue* InParameter) { UDEditorVectorParameterValue* VectorParam = Cast(InParameter); check(VectorParam && VectorParam->bIsUsedAsChannelMask); const UEnum* ChannelEnum = StaticEnum(); check(ChannelEnum); // Convert from vector to RGBA string int64 ChannelType = 0; if (VectorParam->ParameterValue.R > 0.0f) { ChannelType = EChannelMaskParameterColor::Red; } else if (VectorParam->ParameterValue.G > 0.0f) { ChannelType = EChannelMaskParameterColor::Green; } else if (VectorParam->ParameterValue.B > 0.0f) { ChannelType = EChannelMaskParameterColor::Blue; } else { ChannelType = EChannelMaskParameterColor::Alpha; } return ChannelEnum->GetDisplayNameTextByValue(ChannelType).ToString(); } void FMaterialPropertyHelpers::SetVectorChannelMaskValue(const FString& StringValue, TSharedPtr PropertyHandle, UDEditorParameterValue* InParameter, UObject* MaterialEditorInstance) { UDEditorVectorParameterValue* VectorParam = Cast(InParameter); check(VectorParam && VectorParam->bIsUsedAsChannelMask); const UEnum* ChannelEnum = StaticEnum(); check(ChannelEnum); // Convert from RGBA string to vector int64 ChannelValue = ChannelEnum->GetValueByNameString(StringValue); FLinearColor NewValue; switch (ChannelValue) { case EChannelMaskParameterColor::Red: NewValue = FLinearColor(1.0f, 0.0f, 0.0f, 0.0f); break; case EChannelMaskParameterColor::Green: NewValue = FLinearColor(0.0f, 1.0f, 0.0f, 0.0f); break; case EChannelMaskParameterColor::Blue: NewValue = FLinearColor(0.0f, 0.0f, 1.0f, 0.0f); break; default: NewValue = FLinearColor(0.0f, 0.0f, 0.0f, 1.0f); } // If changed, propagate the update if (VectorParam->ParameterValue != NewValue) { const FScopedTransaction Transaction(LOCTEXT("SetVectorChannelMaskValue", "Set Vector Channel Mask Value")); VectorParam->Modify(); PropertyHandle->NotifyPreChange(); VectorParam->ParameterValue = NewValue; UMaterialEditorInstanceConstant* MaterialInstanceEditor = Cast(MaterialEditorInstance); if (MaterialInstanceEditor) { MaterialInstanceEditor->CopyToSourceInstance(); } PropertyHandle->NotifyPostChange(EPropertyChangeType::ValueSet); } } TArray FMaterialPropertyHelpers::GetAssetFactories(EMaterialParameterAssociation AssetType) { TArray NewAssetFactories; switch (AssetType) { case LayerParameter: { // NewAssetFactories.Add(NewObject()); break; } case BlendParameter: { // NewAssetFactories.Add(NewObject()); break; } case GlobalParameter: break; default: break; } return NewAssetFactories; } TSharedRef FMaterialPropertyHelpers::MakeStackReorderHandle(TSharedPtr InOwningStack) { TSharedRef Handle = SNew(SLayerHandle) .Content() [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .Padding(5.0f, 0.0f) [ SNew(SImage) .Image(FCoreStyle::Get().GetBrush("VerticalBoxDragIndicatorShort")) ] ] .OwningStack(InOwningStack); return Handle; } bool FMaterialPropertyHelpers::OnShouldSetCurveAsset(const FAssetData& AssetData, TSoftObjectPtr InAtlas) { UCurveLinearColorAtlas* Atlas = Cast(InAtlas.Get()); if (!Atlas) { return false; } for (UCurveLinearColor* GradientCurve : Atlas->GradientCurves) { if (!GradientCurve || !GradientCurve->GetOutermost()) { continue; } if (GradientCurve->GetOutermost()->GetPathName() == AssetData.PackageName.ToString()) { return true; } } return false; } bool FMaterialPropertyHelpers::OnShouldFilterCurveAsset(const FAssetData& AssetData, TSoftObjectPtr InAtlas) { return !OnShouldSetCurveAsset(AssetData, InAtlas); } void FMaterialPropertyHelpers::SetPositionFromCurveAsset(const FAssetData& AssetData, TSoftObjectPtr InAtlas, UDEditorScalarParameterValue* InParameter, TSharedPtr PropertyHandle, UObject* MaterialEditorInstance) { UCurveLinearColorAtlas* Atlas = Cast(InAtlas.Get()); UCurveLinearColor* Curve = Cast(AssetData.GetAsset()); if (!Atlas || !Curve) { return; } int32 Index = Atlas->GradientCurves.Find(Curve); if (Index == INDEX_NONE) { return; } float NewValue = (float)Index; // If changed, propagate the update if (InParameter->ParameterValue != NewValue) { const FScopedTransaction Transaction(LOCTEXT("SetScalarAtlasPositionValue", "Set Scalar Atlas Position Value")); InParameter->Modify(); InParameter->AtlasData.Curve = TSoftObjectPtr(FSoftObjectPath(Curve->GetPathName())); InParameter->ParameterValue = NewValue; UMaterialEditorInstanceConstant* MaterialInstanceEditor = Cast(MaterialEditorInstance); if (MaterialInstanceEditor) { MaterialInstanceEditor->CopyToSourceInstance(); } } } void FMaterialPropertyHelpers::ResetCurveToDefault(UDEditorParameterValue* Parameter, UMaterialEditorInstanceConstant* MaterialEditorInstance) { const FScopedTransaction Transaction(LOCTEXT("ResetToDefault", "Reset To Default")); Parameter->Modify(); const FMaterialParameterInfo& ParameterInfo = Parameter->ParameterInfo; UDEditorScalarParameterValue* ScalarParam = Cast(Parameter); if (ScalarParam) { float OutValue; if (MaterialEditorInstance->SourceInstance->GetScalarParameterDefaultValue(ParameterInfo, OutValue)) { ScalarParam->ParameterValue = OutValue; // Purge cached values, which will cause non-default values for the atlas data to be returned by IsScalarParameterUsedAsAtlasPosition MaterialEditorInstance->SourceInstance->ClearParameterValuesEditorOnly(); // Update the atlas data from default values bool TempBool; MaterialEditorInstance->SourceInstance->IsScalarParameterUsedAsAtlasPosition(ParameterInfo, TempBool, ScalarParam->AtlasData.Curve, ScalarParam->AtlasData.Atlas); MaterialEditorInstance->CopyToSourceInstance(); } } } #undef LOCTEXT_NAMESPACE