You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Basic approach is to add HLSL types FLWCScalar, FLWCMatrix, FLWCVector, etc. Inside shaders, absolute world space position values should be represented as FLWCVector3. Matrices that transform *into* absolute world space become FLWCMatrix. Matrices that transform *from* world space become FLWCInverseMatrix. Generally LWC values work by extending the regular 'float' value with an additional tile coordinate. Final tile size will be a trade-off between scale/accuracy; I'm using 256k for now, but may need to be adjusted. Value represented by a FLWCVector thus becomes V.Tile * TileSize + V.Offset. Most operations can be performed directly on LWC values. There are HLSL functions like LWCAdd, LWCSub, LWCMultiply, LWCDivide (operator overloading would be really nice here). The goal is to stay with LWC values for as long as needed, then convert to regular float values when possible. One thing that comes up a lot is working in translated (rather than absolute) world space. WorldSpace + View.PrevPreViewTranslation = TranslatedWorldspace. Except 'View.PrevPreViewTranslation' is now a FLWCVector3, and WorldSpace quantities should be as well. So that becomes LWCAdd(WorldSpace, View.PrevPreViewTranslation) = TranslatedWorldspace. Assuming that we're talking about a position that's "reasonably close" to the camera, it should be safe to convert the translated WS value to float. The 'tile' coordinate of the 2 LWC values should cancel out when added together in this case. I've done some work throughout the shader code to do this. Materials are fully supporting LWC-values as well. Projective texturing and vertex animation materials that I've tested work correctly even when positioned "far away" from the origin. Lots of work remains to fully convert all of our shader code. There's a function LWCHackToFloat(), which is a simple wrapper for LWCToFloat(). The idea of HackToFloat is to mark places that need further attention, where I'm simply converting absolute WS positions to float, to get shaders to compile. Shaders converted in this way should continue to work for all existing content (without LWC-scale values), but they will break if positions get too large. General overview of changed files: LargeWorldCoordinates.ush - This defines the FLWC types and operations GPUScene.cpp, SceneData.ush - Primitives add an extra 'float3' tile coordinate. Instance data is unchanged, so instances need to stay within single-precision range of the primitive origin. Could potentially split instances behind the scenes (I think) if we don't want this limitation HLSLMaterialDerivativeAutogen.cpp, HLSLMaterialTranslator.cpp, Preshader.cpp - Translated materials to use LWC values SceneView.cpp, SceneRelativeViewMatrices.cpp, ShaderCompiler.cpp, InstancedStereo.ush - View uniform buffer includes LWC values where appropriate #jira UE-117101 #rb arne.schober, Michael.Galetzka #ROBOMERGE-AUTHOR: ben.ingram #ROBOMERGE-SOURCE: CL 17787435 in //UE5/Main/... #ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v881-17767770) [CL 17787478 by ben ingram in ue5-release-engine-test branch]
1464 lines
68 KiB
C++
1464 lines
68 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "MaterialEditorInstanceDetailCustomization.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 "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/MaterialInterface.h"
|
|
#include "Materials/MaterialInstance.h"
|
|
#include "Materials/MaterialExpressionParameter.h"
|
|
#include "Materials/MaterialExpressionTextureSampleParameter.h"
|
|
#include "Materials/MaterialExpressionFontSampleParameter.h"
|
|
#include "Materials/MaterialExpressionMaterialAttributeLayers.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 "MaterialPropertyHelpers.h"
|
|
#include "Widgets/Input/SButton.h"
|
|
#include "Widgets/Layout/SBox.h"
|
|
#include "Factories/MaterialInstanceConstantFactoryNew.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "AssetToolsModule.h"
|
|
#include "Materials/MaterialFunctionInterface.h"
|
|
#include "Materials/MaterialFunction.h"
|
|
#include "Materials/MaterialFunctionInstance.h"
|
|
#include "Curves/CurveLinearColor.h"
|
|
#include "IPropertyUtilities.h"
|
|
#include "Engine/Texture.h"
|
|
#include "HAL/PlatformApplicationMisc.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "MaterialInstanceEditor"
|
|
|
|
|
|
|
|
TSharedRef<IDetailCustomization> FMaterialInstanceParameterDetails::MakeInstance(UMaterialEditorInstanceConstant* MaterialInstance, FGetShowHiddenParameters InShowHiddenDelegate)
|
|
{
|
|
return MakeShareable(new FMaterialInstanceParameterDetails(MaterialInstance, InShowHiddenDelegate));
|
|
}
|
|
|
|
FMaterialInstanceParameterDetails::FMaterialInstanceParameterDetails(UMaterialEditorInstanceConstant* MaterialInstance, FGetShowHiddenParameters InShowHiddenDelegate)
|
|
: MaterialEditorInstance(MaterialInstance)
|
|
, ShowHiddenDelegate(InShowHiddenDelegate)
|
|
{
|
|
}
|
|
|
|
TOptional<float> FMaterialInstanceParameterDetails::OnGetValue(TSharedRef<IPropertyHandle> PropertyHandle)
|
|
{
|
|
float Value = 0.0f;
|
|
if (PropertyHandle->GetValue(Value) == FPropertyAccess::Success)
|
|
{
|
|
return TOptional<float>(Value);
|
|
}
|
|
|
|
// Value couldn't be accessed. Return an unset value
|
|
return TOptional<float>();
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::OnValueCommitted(float NewValue, ETextCommit::Type CommitType, TSharedRef<IPropertyHandle> PropertyHandle)
|
|
{
|
|
// Try setting as float, if that fails then set as int
|
|
ensure(PropertyHandle->SetValue(NewValue) == FPropertyAccess::Success);
|
|
}
|
|
|
|
FString FMaterialInstanceParameterDetails::GetFunctionParentPath() const
|
|
{
|
|
FString PathString;
|
|
if (MaterialEditorInstance->SourceFunction)
|
|
{
|
|
PathString = MaterialEditorInstance->SourceFunction->Parent->GetPathName();
|
|
}
|
|
return PathString;
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayout)
|
|
{
|
|
PropertyUtilities = DetailLayout.GetPropertyUtilities();
|
|
|
|
// Create a new category for a custom layout for the MIC parameters at the very top
|
|
FName GroupsCategoryName = TEXT("ParameterGroups");
|
|
IDetailCategoryBuilder& GroupsCategory = DetailLayout.EditCategory(GroupsCategoryName, LOCTEXT("MICParamGroupsTitle", "Parameter Groups"));
|
|
TSharedRef<IPropertyHandle> ParameterGroupsProperty = DetailLayout.GetProperty("ParameterGroups");
|
|
|
|
CreateGroupsWidget(ParameterGroupsProperty, GroupsCategory);
|
|
|
|
// Create default category for class properties
|
|
const FName DefaultCategoryName = NAME_None;
|
|
IDetailCategoryBuilder& DefaultCategory = DetailLayout.EditCategory(DefaultCategoryName);
|
|
DetailLayout.HideProperty("MaterialLayersParameterValues");
|
|
if (MaterialEditorInstance->bIsFunctionPreviewMaterial)
|
|
{
|
|
// Customize Parent property so we can check for recursively set parents
|
|
bool bShowParent = false;
|
|
if(MaterialEditorInstance->SourceFunction->GetMaterialFunctionUsage() != EMaterialFunctionUsage::Default)
|
|
{
|
|
bShowParent = true;
|
|
}
|
|
if (bShowParent)
|
|
{
|
|
TSharedRef<IPropertyHandle> ParentPropertyHandle = DetailLayout.GetProperty("Parent");
|
|
IDetailPropertyRow& ParentPropertyRow = DefaultCategory.AddProperty(ParentPropertyHandle);
|
|
ParentPropertyHandle->MarkResetToDefaultCustomized();
|
|
|
|
TSharedPtr<SWidget> NameWidget;
|
|
TSharedPtr<SWidget> ValueWidget;
|
|
FDetailWidgetRow Row;
|
|
|
|
ParentPropertyRow.GetDefaultWidgets(NameWidget, ValueWidget, Row);
|
|
|
|
ParentPropertyHandle->ClearResetToDefaultCustomized();
|
|
|
|
const bool bShowChildren = true;
|
|
ParentPropertyRow.CustomWidget(bShowChildren)
|
|
.NameContent()
|
|
.MinDesiredWidth(Row.NameWidget.MinWidth)
|
|
.MaxDesiredWidth(Row.NameWidget.MaxWidth)
|
|
[
|
|
NameWidget.ToSharedRef()
|
|
]
|
|
.ValueContent()
|
|
.MinDesiredWidth(Row.ValueWidget.MinWidth)
|
|
.MaxDesiredWidth(Row.ValueWidget.MaxWidth)
|
|
[
|
|
SNew(SObjectPropertyEntryBox)
|
|
.ObjectPath(this, &FMaterialInstanceParameterDetails::GetFunctionParentPath)
|
|
.AllowedClass(UMaterialFunctionInterface::StaticClass())
|
|
.ThumbnailPool(DetailLayout.GetThumbnailPool())
|
|
.AllowClear(true)
|
|
.OnObjectChanged(this, &FMaterialInstanceParameterDetails::OnAssetChanged, ParentPropertyHandle)
|
|
.OnShouldSetAsset(this, &FMaterialInstanceParameterDetails::OnShouldSetAsset)
|
|
.NewAssetFactories(TArray<UFactory*>())
|
|
];
|
|
|
|
ValueWidget.Reset();
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
DetailLayout.HideProperty("Parent");
|
|
}
|
|
|
|
DetailLayout.HideProperty("PhysMaterial");
|
|
DetailLayout.HideProperty("LightmassSettings");
|
|
DetailLayout.HideProperty("bUseOldStyleMICEditorGroups");
|
|
DetailLayout.HideProperty("ParameterGroups");
|
|
DetailLayout.HideProperty("RefractionDepthBias");
|
|
DetailLayout.HideProperty("bOverrideSubsurfaceProfile");
|
|
DetailLayout.HideProperty("SubsurfaceProfile");
|
|
DetailLayout.HideProperty("BasePropertyOverrides");
|
|
}
|
|
else
|
|
{
|
|
// Add PhysMaterial property
|
|
DefaultCategory.AddProperty("PhysMaterial");
|
|
|
|
// Customize Parent property so we can check for recursively set parents
|
|
TSharedRef<IPropertyHandle> ParentPropertyHandle = DetailLayout.GetProperty("Parent");
|
|
IDetailPropertyRow& ParentPropertyRow = DefaultCategory.AddProperty(ParentPropertyHandle);
|
|
|
|
ParentPropertyHandle->MarkResetToDefaultCustomized();
|
|
|
|
TSharedPtr<SWidget> NameWidget;
|
|
TSharedPtr<SWidget> ValueWidget;
|
|
FDetailWidgetRow Row;
|
|
|
|
ParentPropertyRow.GetDefaultWidgets(NameWidget, ValueWidget, Row);
|
|
|
|
ParentPropertyHandle->ClearResetToDefaultCustomized();
|
|
|
|
const bool bShowChildren = true;
|
|
ParentPropertyRow.CustomWidget(bShowChildren)
|
|
.NameContent()
|
|
.MinDesiredWidth(Row.NameWidget.MinWidth)
|
|
.MaxDesiredWidth(Row.NameWidget.MaxWidth)
|
|
[
|
|
NameWidget.ToSharedRef()
|
|
]
|
|
.ValueContent()
|
|
.MinDesiredWidth(Row.ValueWidget.MinWidth)
|
|
.MaxDesiredWidth(Row.ValueWidget.MaxWidth)
|
|
[
|
|
SNew(SObjectPropertyEntryBox)
|
|
.PropertyHandle(ParentPropertyHandle)
|
|
.AllowedClass(UMaterialInterface::StaticClass())
|
|
.ThumbnailPool(DetailLayout.GetThumbnailPool())
|
|
.AllowClear(true)
|
|
.OnShouldSetAsset(this, &FMaterialInstanceParameterDetails::OnShouldSetAsset)
|
|
];
|
|
|
|
ValueWidget.Reset();
|
|
|
|
|
|
// Add/hide other properties
|
|
DetailLayout.HideProperty("LightmassSettings");
|
|
CreateLightmassOverrideWidgets(DetailLayout);
|
|
DetailLayout.HideProperty("bUseOldStyleMICEditorGroups");
|
|
DetailLayout.HideProperty("ParameterGroups");
|
|
|
|
{
|
|
FIsResetToDefaultVisible IsRefractionDepthBiasPropertyResetVisible = FIsResetToDefaultVisible::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
float BiasValue;
|
|
float ParentBiasValue;
|
|
return MaterialEditorInstance->SourceInstance->GetRefractionSettings(BiasValue)
|
|
&& MaterialEditorInstance->Parent->GetRefractionSettings(ParentBiasValue)
|
|
&& BiasValue != ParentBiasValue;
|
|
});
|
|
FResetToDefaultHandler ResetRefractionDepthBiasPropertyHandler = FResetToDefaultHandler::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
MaterialEditorInstance->Parent->GetRefractionSettings(MaterialEditorInstance->RefractionDepthBias);
|
|
});
|
|
FResetToDefaultOverride ResetRefractionDepthBiasPropertyOverride = FResetToDefaultOverride::Create(IsRefractionDepthBiasPropertyResetVisible, ResetRefractionDepthBiasPropertyHandler);
|
|
IDetailPropertyRow& PropertyRow = DefaultCategory.AddProperty("RefractionDepthBias");
|
|
PropertyRow.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::ShouldShowMaterialRefractionSettings)));
|
|
PropertyRow.OverrideResetToDefault(ResetRefractionDepthBiasPropertyOverride);
|
|
}
|
|
|
|
{
|
|
// Add the material property override group
|
|
static FName GroupName(TEXT("MaterialPropertyOverrideGroup"));
|
|
IDetailGroup& MaterialPropertyOverrideGroup = DefaultCategory.AddGroup(GroupName, LOCTEXT("MaterialPropertyOverrideGroup", "Material Property Overrides"), false, false);
|
|
|
|
// Hide the originals, these will be recreated manually
|
|
DetailLayout.HideProperty("bOverrideSubsurfaceProfile");
|
|
DetailLayout.HideProperty("SubsurfaceProfile");
|
|
DetailLayout.HideProperty("BasePropertyOverrides");
|
|
|
|
// Set up the override logic for the subsurface profile
|
|
TAttribute<bool> IsParamEnabled = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateLambda([this](){ return (bool)MaterialEditorInstance->bOverrideSubsurfaceProfile; }));
|
|
|
|
IDetailPropertyRow& PropertyRow = MaterialPropertyOverrideGroup.AddPropertyRow(DetailLayout.GetProperty("SubsurfaceProfile"));
|
|
PropertyRow
|
|
.EditCondition(IsParamEnabled,
|
|
FOnBooleanValueChanged::CreateLambda([this](bool NewValue) {
|
|
MaterialEditorInstance->bOverrideSubsurfaceProfile = (uint32)NewValue;
|
|
MaterialEditorInstance->PostEditChange();
|
|
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
|
|
}))
|
|
.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::ShouldShowSubsurfaceProfile)));
|
|
|
|
// Append the base property overrides to the Material Property Override Group
|
|
CreateBasePropertyOverrideWidgets(DetailLayout, MaterialPropertyOverrideGroup);
|
|
}
|
|
}
|
|
|
|
// Add the preview mesh property directly from the material instance
|
|
FName PreviewingCategoryName = TEXT("Previewing");
|
|
IDetailCategoryBuilder& PreviewingCategory = DetailLayout.EditCategory(PreviewingCategoryName, LOCTEXT("MICPreviewingCategoryTitle", "Previewing"));
|
|
|
|
TArray<UObject*> ExternalObjects;
|
|
ExternalObjects.Add(MaterialEditorInstance->SourceInstance);
|
|
|
|
PreviewingCategory.AddExternalObjectProperty(ExternalObjects, TEXT("PreviewMesh"));
|
|
|
|
DefaultCategory.AddExternalObjectProperty(ExternalObjects, TEXT("AssetUserData"), EPropertyLocation::Advanced);
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::CreateGroupsWidget(TSharedRef<IPropertyHandle> ParameterGroupsProperty, IDetailCategoryBuilder& GroupsCategory)
|
|
{
|
|
bool bShowSaveButtons = false;
|
|
check(MaterialEditorInstance);
|
|
for (int32 GroupIdx = 0; GroupIdx < MaterialEditorInstance->ParameterGroups.Num(); ++GroupIdx)
|
|
{
|
|
FEditorParameterGroup& ParameterGroup = MaterialEditorInstance->ParameterGroups[GroupIdx];
|
|
if (ParameterGroup.GroupAssociation == EMaterialParameterAssociation::GlobalParameter
|
|
&& ParameterGroup.GroupName != FMaterialPropertyHelpers::LayerParamName)
|
|
{
|
|
bShowSaveButtons = true;
|
|
bool bCreateGroup = false;
|
|
bool bIsCookedMaterial = false;
|
|
if (MaterialEditorInstance->SourceInstance)
|
|
{
|
|
if (UMaterial* Material = MaterialEditorInstance->SourceInstance->GetMaterial())
|
|
{
|
|
bIsCookedMaterial = Material->GetPackage()->HasAnyPackageFlags(PKG_Cooked);
|
|
}
|
|
}
|
|
for (int32 ParamIdx = 0; ParamIdx < ParameterGroup.Parameters.Num() && !bCreateGroup; ++ParamIdx)
|
|
{
|
|
UDEditorParameterValue* Parameter = ParameterGroup.Parameters[ParamIdx];
|
|
// All parameters on cooked materials are visible since the underlying data to discover visibility has been stripped.
|
|
const bool bIsVisible = bIsCookedMaterial || MaterialEditorInstance->VisibleExpressions.Contains(Parameter->ParameterInfo);
|
|
bCreateGroup = bIsVisible && (!MaterialEditorInstance->bShowOnlyOverrides || FMaterialPropertyHelpers::IsOverriddenExpression(Parameter));
|
|
}
|
|
|
|
if (bCreateGroup)
|
|
{
|
|
IDetailGroup& DetailGroup = GroupsCategory.AddGroup(ParameterGroup.GroupName, FText::FromName(ParameterGroup.GroupName), false, true);
|
|
|
|
FUIAction CopyAction(
|
|
FExecuteAction::CreateSP(this, &FMaterialInstanceParameterDetails::OnCopyParameterValues, GroupIdx),
|
|
FCanExecuteAction::CreateSP(this, &FMaterialInstanceParameterDetails::CanCopyParameterValues, GroupIdx));
|
|
FUIAction PasteAction(
|
|
FExecuteAction::CreateSP(this, &FMaterialInstanceParameterDetails::OnPasteParameterValues, GroupIdx),
|
|
FCanExecuteAction::CreateSP(this, &FMaterialInstanceParameterDetails::CanPasteParameterValues, GroupIdx));
|
|
DetailGroup.HeaderRow()
|
|
.CopyAction(CopyAction)
|
|
.PasteAction(PasteAction)
|
|
.NameContent()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(FText::FromName(DetailGroup.GetGroupName()))
|
|
];
|
|
|
|
CreateSingleGroupWidget(ParameterGroup, ParameterGroupsProperty->GetChildHandle(GroupIdx), DetailGroup);
|
|
}
|
|
}
|
|
}
|
|
if (bShowSaveButtons)
|
|
{
|
|
FDetailWidgetRow& SaveInstanceRow = GroupsCategory.AddCustomRow(LOCTEXT("SaveInstances", "Save Instances"));
|
|
FOnClicked OnChildButtonClicked;
|
|
FOnClicked OnSiblingButtonClicked;
|
|
UMaterialInterface* LocalSourceInstance = MaterialEditorInstance->SourceInstance;
|
|
UObject* LocalEditorInstance = MaterialEditorInstance;
|
|
if (!MaterialEditorInstance->bIsFunctionPreviewMaterial)
|
|
{
|
|
OnChildButtonClicked = FOnClicked::CreateStatic(&FMaterialPropertyHelpers::OnClickedSaveNewMaterialInstance, LocalSourceInstance, LocalEditorInstance);
|
|
OnSiblingButtonClicked = FOnClicked::CreateStatic(&FMaterialPropertyHelpers::OnClickedSaveNewMaterialInstance, ToRawPtr(MaterialEditorInstance->SourceInstance->Parent), LocalEditorInstance);
|
|
}
|
|
else
|
|
{
|
|
OnChildButtonClicked = FOnClicked::CreateStatic(&FMaterialPropertyHelpers::OnClickedSaveNewFunctionInstance,
|
|
ImplicitConv<UMaterialFunctionInterface*>(MaterialEditorInstance->SourceFunction), LocalSourceInstance, LocalEditorInstance);
|
|
OnSiblingButtonClicked = FOnClicked::CreateStatic(&FMaterialPropertyHelpers::OnClickedSaveNewFunctionInstance,
|
|
ImplicitConv<UMaterialFunctionInterface*>(MaterialEditorInstance->SourceFunction->Parent), LocalSourceInstance, LocalEditorInstance);
|
|
}
|
|
SaveInstanceRow.ValueContent()
|
|
.HAlign(HAlign_Fill)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth(1.0f)
|
|
[
|
|
SNullWidget::NullWidget
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding(2.0f)
|
|
[
|
|
SNew(SButton)
|
|
.Text(LOCTEXT("SaveSibling", "Save Sibling"))
|
|
.HAlign(HAlign_Center)
|
|
.OnClicked(OnSiblingButtonClicked)
|
|
.ToolTipText(LOCTEXT("SaveToSiblingInstance", "Save to Sibling Instance"))
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding(2.0f)
|
|
[
|
|
SNew(SButton)
|
|
.Text(LOCTEXT("SaveChild", "Save Child"))
|
|
.HAlign(HAlign_Center)
|
|
.OnClicked(OnChildButtonClicked)
|
|
.ToolTipText(LOCTEXT("SaveToChildInstance", "Save to Child Instance"))
|
|
]
|
|
];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void FMaterialInstanceParameterDetails::CreateSingleGroupWidget(FEditorParameterGroup& ParameterGroup, TSharedPtr<IPropertyHandle> ParameterGroupProperty, IDetailGroup& DetailGroup )
|
|
{
|
|
TSharedPtr<IPropertyHandle> ParametersArrayProperty = ParameterGroupProperty->GetChildHandle("Parameters");
|
|
|
|
// Create a custom widget for each parameter in the group
|
|
for (int32 ParamIdx = 0; ParamIdx < ParameterGroup.Parameters.Num(); ++ParamIdx)
|
|
{
|
|
TSharedPtr<IPropertyHandle> ParameterProperty = ParametersArrayProperty->GetChildHandle(ParamIdx);
|
|
|
|
UDEditorParameterValue* Parameter = ParameterGroup.Parameters[ParamIdx];
|
|
UDEditorFontParameterValue* FontParam = Cast<UDEditorFontParameterValue>(Parameter);
|
|
UDEditorMaterialLayersParameterValue* LayersParam = Cast<UDEditorMaterialLayersParameterValue>(Parameter);
|
|
UDEditorScalarParameterValue* ScalarParam = Cast<UDEditorScalarParameterValue>(Parameter);
|
|
UDEditorStaticComponentMaskParameterValue* CompMaskParam = Cast<UDEditorStaticComponentMaskParameterValue>(Parameter);
|
|
UDEditorStaticSwitchParameterValue* SwitchParam = Cast<UDEditorStaticSwitchParameterValue>(Parameter);
|
|
UDEditorTextureParameterValue* TextureParam = Cast<UDEditorTextureParameterValue>(Parameter);
|
|
UDEditorRuntimeVirtualTextureParameterValue* RuntimeVirtualTextureParam = Cast<UDEditorRuntimeVirtualTextureParameterValue>(Parameter);
|
|
UDEditorVectorParameterValue* VectorParam = Cast<UDEditorVectorParameterValue>(Parameter);
|
|
|
|
if (Parameter->ParameterInfo.Association == EMaterialParameterAssociation::GlobalParameter)
|
|
{
|
|
if (VectorParam && VectorParam->bIsUsedAsChannelMask)
|
|
{
|
|
CreateVectorChannelMaskParameterValueWidget(Parameter, ParameterProperty, DetailGroup);
|
|
}
|
|
if (ScalarParam && ScalarParam->AtlasData.bIsUsedAsAtlasPosition)
|
|
{
|
|
CreateScalarAtlasPositionParameterValueWidget(Parameter, ParameterProperty, DetailGroup);
|
|
}
|
|
if (TextureParam &&
|
|
( !TextureParam->ChannelNames.R.IsEmpty()
|
|
|| !TextureParam->ChannelNames.G.IsEmpty()
|
|
|| !TextureParam->ChannelNames.B.IsEmpty()
|
|
|| !TextureParam->ChannelNames.A.IsEmpty()))
|
|
{
|
|
CreateLabeledTextureParameterValueWidget(Parameter, ParameterProperty, DetailGroup);
|
|
}
|
|
else if (LayersParam)
|
|
{
|
|
}
|
|
else if (CompMaskParam)
|
|
{
|
|
CreateMaskParameterValueWidget(Parameter, ParameterProperty, DetailGroup);
|
|
}
|
|
else
|
|
{
|
|
if (ScalarParam && ScalarParam->SliderMax > ScalarParam->SliderMin)
|
|
{
|
|
TSharedPtr<IPropertyHandle> ParameterValueProperty = ParameterProperty->GetChildHandle("ParameterValue");
|
|
ParameterValueProperty->SetInstanceMetaData("UIMin", FString::Printf(TEXT("%f"), ScalarParam->SliderMin));
|
|
ParameterValueProperty->SetInstanceMetaData("UIMax", FString::Printf(TEXT("%f"), ScalarParam->SliderMax));
|
|
}
|
|
|
|
if (VectorParam)
|
|
{
|
|
static const FName Red("R");
|
|
static const FName Green("G");
|
|
static const FName Blue("B");
|
|
static const FName Alpha("A");
|
|
if (!VectorParam->ChannelNames.R.IsEmpty())
|
|
{
|
|
ParameterProperty->GetChildHandle(Red)->SetPropertyDisplayName(VectorParam->ChannelNames.R);
|
|
}
|
|
if (!VectorParam->ChannelNames.G.IsEmpty())
|
|
{
|
|
ParameterProperty->GetChildHandle(Green)->SetPropertyDisplayName(VectorParam->ChannelNames.G);
|
|
}
|
|
if (!VectorParam->ChannelNames.B.IsEmpty())
|
|
{
|
|
ParameterProperty->GetChildHandle(Blue)->SetPropertyDisplayName(VectorParam->ChannelNames.B);
|
|
}
|
|
if (!VectorParam->ChannelNames.A.IsEmpty())
|
|
{
|
|
ParameterProperty->GetChildHandle(Alpha)->SetPropertyDisplayName(VectorParam->ChannelNames.A);
|
|
}
|
|
}
|
|
|
|
CreateParameterValueWidget(Parameter, ParameterProperty, DetailGroup);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::CreateParameterValueWidget(UDEditorParameterValue* Parameter, TSharedPtr<IPropertyHandle> ParameterProperty, IDetailGroup& DetailGroup)
|
|
{
|
|
TSharedPtr<IPropertyHandle> ParameterValueProperty = ParameterProperty->GetChildHandle("ParameterValue");
|
|
|
|
if (ParameterValueProperty->IsValidHandle())
|
|
{
|
|
TAttribute<bool> IsParamEnabled = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateStatic(&FMaterialPropertyHelpers::IsOverriddenExpression, Parameter));
|
|
|
|
IDetailPropertyRow& PropertyRow = DetailGroup.AddPropertyRow(ParameterValueProperty.ToSharedRef());
|
|
|
|
TAttribute<bool> IsResetVisible = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateStatic(&FMaterialPropertyHelpers::ShouldShowResetToDefault, Parameter, MaterialEditorInstance));
|
|
FSimpleDelegate ResetHandler = FSimpleDelegate::CreateStatic(&FMaterialPropertyHelpers::ResetToDefault, Parameter, MaterialEditorInstance);
|
|
FResetToDefaultOverride ResetOverride = FResetToDefaultOverride::Create(IsResetVisible, ResetHandler);
|
|
|
|
PropertyRow
|
|
.DisplayName(FText::FromName(Parameter->ParameterInfo.Name))
|
|
.ToolTip(FMaterialPropertyHelpers::GetParameterTooltip(Parameter, MaterialEditorInstance))
|
|
.EditCondition(IsParamEnabled, FOnBooleanValueChanged::CreateStatic(&FMaterialPropertyHelpers::OnOverrideParameter, Parameter, MaterialEditorInstance))
|
|
.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateStatic(&FMaterialPropertyHelpers::ShouldShowExpression, Parameter, MaterialEditorInstance, ShowHiddenDelegate)))
|
|
.OverrideResetToDefault(ResetOverride);
|
|
|
|
// Textures need a special widget that filters based on VT or not
|
|
UDEditorTextureParameterValue* TextureParam = Cast<UDEditorTextureParameterValue>(Parameter);
|
|
if (TextureParam != nullptr)
|
|
{
|
|
UMaterial *Material = MaterialEditorInstance->SourceInstance->GetMaterial();
|
|
if (Material != nullptr)
|
|
{
|
|
UMaterialExpressionTextureSampleParameter* Expression = Material->FindExpressionByGUID<UMaterialExpressionTextureSampleParameter>(TextureParam->ExpressionId);
|
|
if (Expression != nullptr)
|
|
{
|
|
TWeakObjectPtr<UMaterialExpressionTextureSampleParameter> SamplerExpression = Expression;
|
|
|
|
PropertyRow.CustomWidget()
|
|
.NameContent()
|
|
[
|
|
ParameterValueProperty->CreatePropertyNameWidget()
|
|
]
|
|
.ValueContent()
|
|
.MaxDesiredWidth(TOptional<float>())
|
|
[
|
|
SNew(SObjectPropertyEntryBox)
|
|
.PropertyHandle(ParameterValueProperty)
|
|
.AllowedClass(UTexture::StaticClass())
|
|
.ThumbnailPool(PropertyUtilities.Pin()->GetThumbnailPool())
|
|
.OnShouldFilterAsset_Lambda([SamplerExpression](const FAssetData& AssetData)
|
|
{
|
|
if (SamplerExpression.Get())
|
|
{
|
|
bool VirtualTextured = false;
|
|
AssetData.GetTagValue<bool>("VirtualTextureStreaming", VirtualTextured);
|
|
|
|
bool ExpressionIsVirtualTextured = IsVirtualSamplerType(SamplerExpression->SamplerType);
|
|
|
|
return VirtualTextured != ExpressionIsVirtualTextured;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
})
|
|
];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::CreateMaskParameterValueWidget(UDEditorParameterValue* Parameter, TSharedPtr<IPropertyHandle> ParameterProperty, IDetailGroup& DetailGroup )
|
|
{
|
|
TSharedPtr<IPropertyHandle> ParameterValueProperty = ParameterProperty->GetChildHandle("ParameterValue");
|
|
TSharedPtr<IPropertyHandle> RMaskProperty = ParameterValueProperty->GetChildHandle("R");
|
|
TSharedPtr<IPropertyHandle> GMaskProperty = ParameterValueProperty->GetChildHandle("G");
|
|
TSharedPtr<IPropertyHandle> BMaskProperty = ParameterValueProperty->GetChildHandle("B");
|
|
TSharedPtr<IPropertyHandle> AMaskProperty = ParameterValueProperty->GetChildHandle("A");
|
|
|
|
if (ParameterValueProperty->IsValidHandle())
|
|
{
|
|
TAttribute<bool> IsParamEnabled = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateStatic(&FMaterialPropertyHelpers::IsOverriddenExpression, Parameter));
|
|
|
|
IDetailPropertyRow& PropertyRow = DetailGroup.AddPropertyRow(ParameterValueProperty.ToSharedRef());
|
|
PropertyRow.EditCondition(IsParamEnabled, FOnBooleanValueChanged::CreateStatic(&FMaterialPropertyHelpers::OnOverrideParameter, Parameter, MaterialEditorInstance));
|
|
// Handle reset to default manually
|
|
PropertyRow.OverrideResetToDefault(FResetToDefaultOverride::Create(FSimpleDelegate::CreateStatic(&FMaterialPropertyHelpers::ResetToDefault, Parameter, MaterialEditorInstance)));
|
|
PropertyRow.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateStatic(&FMaterialPropertyHelpers::ShouldShowExpression, Parameter, MaterialEditorInstance, ShowHiddenDelegate)));
|
|
|
|
const FText ParameterName = FText::FromName(Parameter->ParameterInfo.Name);
|
|
|
|
FDetailWidgetRow& CustomWidget = PropertyRow.CustomWidget();
|
|
CustomWidget
|
|
.FilterString(ParameterName)
|
|
.NameContent()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(ParameterName)
|
|
.ToolTipText(FMaterialPropertyHelpers::GetParameterTooltip(Parameter, MaterialEditorInstance))
|
|
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
|
|
]
|
|
.ValueContent()
|
|
.MaxDesiredWidth(200.0f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth(1.0f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Left)
|
|
.AutoWidth()
|
|
[
|
|
RMaskProperty->CreatePropertyNameWidget(FText::GetEmpty(), FText::GetEmpty(), false)
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Left)
|
|
.AutoWidth()
|
|
[
|
|
RMaskProperty->CreatePropertyValueWidget()
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Left)
|
|
.Padding(FMargin(10.0f, 0.0f, 0.0f, 0.0f))
|
|
.AutoWidth()
|
|
[
|
|
GMaskProperty->CreatePropertyNameWidget(FText::GetEmpty(), FText::GetEmpty(), false)
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Left)
|
|
.AutoWidth()
|
|
[
|
|
GMaskProperty->CreatePropertyValueWidget()
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Left)
|
|
.Padding(FMargin(10.0f, 0.0f, 0.0f, 0.0f))
|
|
.AutoWidth()
|
|
[
|
|
BMaskProperty->CreatePropertyNameWidget(FText::GetEmpty(), FText::GetEmpty(), false)
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Left)
|
|
.AutoWidth()
|
|
[
|
|
BMaskProperty->CreatePropertyValueWidget()
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Left)
|
|
.Padding(FMargin(10.0f, 0.0f, 0.0f, 0.0f))
|
|
.AutoWidth()
|
|
[
|
|
AMaskProperty->CreatePropertyNameWidget(FText::GetEmpty(), FText::GetEmpty(), false)
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Left)
|
|
.AutoWidth()
|
|
[
|
|
AMaskProperty->CreatePropertyValueWidget()
|
|
]
|
|
]
|
|
];
|
|
}
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::CreateVectorChannelMaskParameterValueWidget(UDEditorParameterValue* Parameter, TSharedPtr<IPropertyHandle> ParameterProperty, IDetailGroup& DetailGroup)
|
|
{
|
|
TSharedPtr<IPropertyHandle> ParameterValueProperty = ParameterProperty->GetChildHandle("ParameterValue");
|
|
|
|
if (ParameterValueProperty->IsValidHandle())
|
|
{
|
|
TAttribute<bool> IsParamEnabled = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateStatic(&FMaterialPropertyHelpers::IsOverriddenExpression, Parameter));
|
|
|
|
IDetailPropertyRow& PropertyRow = DetailGroup.AddPropertyRow(ParameterValueProperty.ToSharedRef());
|
|
PropertyRow.EditCondition(IsParamEnabled, FOnBooleanValueChanged::CreateStatic(&FMaterialPropertyHelpers::OnOverrideParameter, Parameter, MaterialEditorInstance));
|
|
// Handle reset to default manually
|
|
PropertyRow.OverrideResetToDefault(FResetToDefaultOverride::Create(FSimpleDelegate::CreateStatic(&FMaterialPropertyHelpers::ResetToDefault, Parameter, MaterialEditorInstance)));
|
|
PropertyRow.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateStatic(&FMaterialPropertyHelpers::ShouldShowExpression, Parameter, MaterialEditorInstance, ShowHiddenDelegate)));
|
|
|
|
const FText ParameterName = FText::FromName(Parameter->ParameterInfo.Name);
|
|
|
|
// Combo box hooks for converting between our "enum" and colors
|
|
FOnGetPropertyComboBoxStrings GetMaskStrings = FOnGetPropertyComboBoxStrings::CreateStatic(&FMaterialPropertyHelpers::GetVectorChannelMaskComboBoxStrings);
|
|
FOnGetPropertyComboBoxValue GetMaskValue = FOnGetPropertyComboBoxValue::CreateStatic(&FMaterialPropertyHelpers::GetVectorChannelMaskValue, Parameter);
|
|
FOnPropertyComboBoxValueSelected SetMaskValue = FOnPropertyComboBoxValueSelected::CreateStatic(&FMaterialPropertyHelpers::SetVectorChannelMaskValue, ParameterValueProperty, Parameter, (UObject*)MaterialEditorInstance);
|
|
|
|
// Widget replaces color picker with combo box
|
|
FDetailWidgetRow& CustomWidget = PropertyRow.CustomWidget();
|
|
CustomWidget
|
|
.FilterString(ParameterName)
|
|
.NameContent()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(ParameterName)
|
|
.ToolTipText(FMaterialPropertyHelpers::GetParameterTooltip(Parameter, MaterialEditorInstance))
|
|
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
|
|
]
|
|
.ValueContent()
|
|
.MaxDesiredWidth(200.0f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth(1.0f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Left)
|
|
.AutoWidth()
|
|
[
|
|
PropertyCustomizationHelpers::MakePropertyComboBox(ParameterValueProperty, GetMaskStrings, GetMaskValue, SetMaskValue)
|
|
]
|
|
]
|
|
];
|
|
}
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::CreateScalarAtlasPositionParameterValueWidget(class UDEditorParameterValue* Parameter, TSharedPtr<IPropertyHandle> ParameterProperty, IDetailGroup& DetailGroup)
|
|
{
|
|
TSharedPtr<IPropertyHandle> ParameterValueProperty = ParameterProperty->GetChildHandle("ParameterValue");
|
|
|
|
if (ParameterValueProperty->IsValidHandle())
|
|
{
|
|
TAttribute<bool> IsParamEnabled = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateStatic(&FMaterialPropertyHelpers::IsOverriddenExpression, Parameter));
|
|
|
|
IDetailPropertyRow& PropertyRow = DetailGroup.AddPropertyRow(ParameterValueProperty.ToSharedRef());
|
|
PropertyRow.EditCondition(IsParamEnabled, FOnBooleanValueChanged::CreateStatic(&FMaterialPropertyHelpers::OnOverrideParameter, Parameter, MaterialEditorInstance));
|
|
// Handle reset to default manually
|
|
PropertyRow.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateStatic(&FMaterialPropertyHelpers::ShouldShowExpression, Parameter, MaterialEditorInstance, ShowHiddenDelegate)));
|
|
|
|
const FText ParameterName = FText::FromName(Parameter->ParameterInfo.Name);
|
|
UDEditorScalarParameterValue* AtlasParameter = Cast<UDEditorScalarParameterValue>(Parameter);
|
|
|
|
TAttribute<bool> IsResetVisible = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateStatic(&FMaterialPropertyHelpers::ShouldShowResetToDefault, Parameter, MaterialEditorInstance));
|
|
FSimpleDelegate ResetHandler = FSimpleDelegate::CreateStatic(&FMaterialPropertyHelpers::ResetCurveToDefault, Parameter, MaterialEditorInstance);
|
|
FResetToDefaultOverride ResetOverride = FResetToDefaultOverride::Create(IsResetVisible, ResetHandler);
|
|
|
|
PropertyRow.OverrideResetToDefault(ResetOverride);
|
|
|
|
FDetailWidgetRow& CustomWidget = PropertyRow.CustomWidget();
|
|
CustomWidget
|
|
.FilterString(ParameterName)
|
|
.NameContent()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(ParameterName)
|
|
.ToolTipText(FMaterialPropertyHelpers::GetParameterTooltip(Parameter, MaterialEditorInstance))
|
|
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
|
|
]
|
|
.ValueContent()
|
|
.HAlign(HAlign_Fill)
|
|
.MaxDesiredWidth(400.0f)
|
|
[
|
|
SNew(SObjectPropertyEntryBox)
|
|
.ObjectPath(this, &FMaterialInstanceParameterDetails::GetCurvePath, AtlasParameter)
|
|
.AllowedClass(UCurveLinearColor::StaticClass())
|
|
.NewAssetFactories(TArray<UFactory*>())
|
|
.DisplayThumbnail(true)
|
|
.ThumbnailPool(PropertyUtilities.Pin()->GetThumbnailPool())
|
|
.OnShouldFilterAsset(FOnShouldFilterAsset::CreateStatic(&FMaterialPropertyHelpers::OnShouldFilterCurveAsset, AtlasParameter->AtlasData.Atlas))
|
|
.OnShouldSetAsset(FOnShouldSetAsset::CreateStatic(&FMaterialPropertyHelpers::OnShouldSetCurveAsset, AtlasParameter->AtlasData.Atlas))
|
|
.OnObjectChanged(FOnSetObject::CreateStatic(&FMaterialPropertyHelpers::SetPositionFromCurveAsset, AtlasParameter->AtlasData.Atlas, AtlasParameter, ParameterProperty, (UObject*)MaterialEditorInstance))
|
|
.DisplayCompactSize(true)
|
|
];
|
|
}
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::CreateLabeledTextureParameterValueWidget(class UDEditorParameterValue* Parameter, TSharedPtr<IPropertyHandle> ParameterProperty, IDetailGroup& DetailGroup)
|
|
{
|
|
TSharedPtr<IPropertyHandle> ParameterValueProperty = ParameterProperty->GetChildHandle("ParameterValue");
|
|
|
|
if (ParameterValueProperty->IsValidHandle())
|
|
{
|
|
UDEditorTextureParameterValue* TextureParam = Cast<UDEditorTextureParameterValue>(Parameter);
|
|
if (TextureParam)
|
|
{
|
|
UMaterial *Material = MaterialEditorInstance->SourceInstance->GetMaterial();
|
|
if (Material != nullptr)
|
|
{
|
|
UMaterialExpressionTextureSampleParameter* Expression = Material->FindExpressionByGUID<UMaterialExpressionTextureSampleParameter>(TextureParam->ExpressionId);
|
|
if (Expression != nullptr)
|
|
{
|
|
TWeakObjectPtr<UMaterialExpressionTextureSampleParameter> SamplerExpression = Expression;
|
|
TAttribute<bool> IsParamEnabled = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateStatic(&FMaterialPropertyHelpers::IsOverriddenExpression, Parameter));
|
|
|
|
IDetailPropertyRow& PropertyRow = DetailGroup.AddPropertyRow(ParameterValueProperty.ToSharedRef());
|
|
|
|
TAttribute<bool> IsResetVisible = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateStatic(&FMaterialPropertyHelpers::ShouldShowResetToDefault, Parameter, MaterialEditorInstance));
|
|
FSimpleDelegate ResetHandler = FSimpleDelegate::CreateStatic(&FMaterialPropertyHelpers::ResetToDefault, Parameter, MaterialEditorInstance);
|
|
FResetToDefaultOverride ResetOverride = FResetToDefaultOverride::Create(IsResetVisible, ResetHandler);
|
|
|
|
PropertyRow
|
|
.DisplayName(FText::FromName(Parameter->ParameterInfo.Name))
|
|
.EditCondition(IsParamEnabled, FOnBooleanValueChanged::CreateStatic(&FMaterialPropertyHelpers::OnOverrideParameter, Parameter, MaterialEditorInstance))
|
|
.ToolTip(FMaterialPropertyHelpers::GetParameterTooltip(Parameter, MaterialEditorInstance))
|
|
.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateStatic(&FMaterialPropertyHelpers::ShouldShowExpression, Parameter, MaterialEditorInstance, ShowHiddenDelegate)))
|
|
.OverrideResetToDefault(ResetOverride);
|
|
|
|
|
|
TSharedPtr<SWidget> NameWidget;
|
|
TSharedPtr<SWidget> ValueWidget;
|
|
FDetailWidgetRow Row;
|
|
PropertyRow.GetDefaultWidgets(NameWidget, ValueWidget, Row);
|
|
|
|
FDetailWidgetRow &DetailWidgetRow = PropertyRow.CustomWidget();
|
|
TSharedPtr<SVerticalBox> NameVerticalBox;
|
|
DetailWidgetRow.NameContent()
|
|
[
|
|
SAssignNew(NameVerticalBox, SVerticalBox)
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(FText::FromName(Parameter->ParameterInfo.Name))
|
|
.ToolTipText(FMaterialPropertyHelpers::GetParameterTooltip(Parameter, MaterialEditorInstance))
|
|
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
|
|
]
|
|
];
|
|
DetailWidgetRow.ValueContent()
|
|
.MinDesiredWidth(Row.ValueWidget.MinWidth)
|
|
.MaxDesiredWidth(Row.ValueWidget.MaxWidth)
|
|
[
|
|
SNew(SObjectPropertyEntryBox)
|
|
.PropertyHandle(ParameterValueProperty)
|
|
.AllowedClass(UTexture::StaticClass())
|
|
.ThumbnailPool(PropertyUtilities.Pin()->GetThumbnailPool())
|
|
.OnShouldFilterAsset_Lambda([SamplerExpression](const FAssetData& AssetData)
|
|
{
|
|
if (SamplerExpression.Get())
|
|
{
|
|
bool VirtualTextured = false;
|
|
AssetData.GetTagValue<bool>("VirtualTextureStreaming", VirtualTextured);
|
|
|
|
bool ExpressionIsVirtualTextured = IsVirtualSamplerType(SamplerExpression->SamplerType);
|
|
|
|
return VirtualTextured != ExpressionIsVirtualTextured;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
})
|
|
];
|
|
|
|
DetailWidgetRow.OverrideResetToDefault(ResetOverride);
|
|
|
|
static const FName Red("R");
|
|
static const FName Green("G");
|
|
static const FName Blue("B");
|
|
static const FName Alpha("A");
|
|
|
|
if (!TextureParam->ChannelNames.R.IsEmpty())
|
|
{
|
|
NameVerticalBox->AddSlot()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding(20.0, 2.0, 4.0, 2.0)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(FText::FromName(Red))
|
|
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.BoldFont")))
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Left)
|
|
.Padding(4.0, 2.0)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(TextureParam->ChannelNames.R)
|
|
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
|
|
]
|
|
];
|
|
}
|
|
if (!TextureParam->ChannelNames.G.IsEmpty())
|
|
{
|
|
NameVerticalBox->AddSlot()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(20.0, 2.0, 4.0, 2.0)
|
|
.AutoWidth()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(FText::FromName(Green))
|
|
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.BoldFont")))
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Left)
|
|
.Padding(4.0, 2.0)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(TextureParam->ChannelNames.G)
|
|
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
|
|
]
|
|
];
|
|
}
|
|
if (!TextureParam->ChannelNames.B.IsEmpty())
|
|
{
|
|
NameVerticalBox->AddSlot()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(20.0, 2.0, 4.0, 2.0)
|
|
.AutoWidth()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(FText::FromName(Blue))
|
|
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.BoldFont")))
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Left)
|
|
.Padding(4.0, 2.0)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(TextureParam->ChannelNames.B)
|
|
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
|
|
]
|
|
];
|
|
}
|
|
if (!TextureParam->ChannelNames.A.IsEmpty())
|
|
{
|
|
NameVerticalBox->AddSlot()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(20.0, 2.0, 4.0, 2.0)
|
|
.AutoWidth()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(FText::FromName(Alpha))
|
|
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.BoldFont")))
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.HAlign(HAlign_Left)
|
|
.Padding(4.0, 2.0)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(TextureParam->ChannelNames.A)
|
|
.Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
|
|
]
|
|
];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FString FMaterialInstanceParameterDetails::GetCurvePath(UDEditorScalarParameterValue* Parameter) const
|
|
{
|
|
FString Path = Parameter->AtlasData.Curve->GetPathName();
|
|
return Path;
|
|
}
|
|
|
|
bool FMaterialInstanceParameterDetails::IsVisibleExpression(UDEditorParameterValue* Parameter)
|
|
{
|
|
return MaterialEditorInstance->VisibleExpressions.Contains(Parameter->ParameterInfo);
|
|
}
|
|
|
|
EVisibility FMaterialInstanceParameterDetails::ShouldShowExpression(UDEditorParameterValue* Parameter) const
|
|
{
|
|
return FMaterialPropertyHelpers::ShouldShowExpression(Parameter, MaterialEditorInstance, ShowHiddenDelegate);
|
|
}
|
|
|
|
bool FMaterialInstanceParameterDetails::OnShouldSetAsset(const FAssetData& AssetData) const
|
|
{
|
|
if (MaterialEditorInstance->bIsFunctionPreviewMaterial)
|
|
{
|
|
if (MaterialEditorInstance->SourceFunction->GetMaterialFunctionUsage() == EMaterialFunctionUsage::Default)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
UMaterialFunctionInstance* FunctionInstance = Cast<UMaterialFunctionInstance>(AssetData.GetAsset());
|
|
if (FunctionInstance != nullptr)
|
|
{
|
|
bool bIsChild = FunctionInstance->IsDependent(MaterialEditorInstance->SourceFunction);
|
|
if (bIsChild)
|
|
{
|
|
FMessageDialog::Open(
|
|
EAppMsgType::Ok,
|
|
FText::Format(LOCTEXT("CannotSetExistingChildFunctionAsParent", "Cannot set {0} as a parent as it is already a child of this material function instance."), FText::FromName(AssetData.AssetName)));
|
|
}
|
|
return !bIsChild;
|
|
}
|
|
}
|
|
}
|
|
|
|
UMaterialInstance* MaterialInstance = Cast<UMaterialInstance>(AssetData.GetAsset());
|
|
|
|
if (MaterialInstance != nullptr)
|
|
{
|
|
bool bIsChild = MaterialInstance->IsChildOf(MaterialEditorInstance->SourceInstance);
|
|
if (bIsChild)
|
|
{
|
|
FMessageDialog::Open(
|
|
EAppMsgType::Ok,
|
|
FText::Format(LOCTEXT("CannotSetExistingChildAsParent", "Cannot set {0} as a parent as it is already a child of this material instance."), FText::FromName(AssetData.AssetName)));
|
|
}
|
|
return !bIsChild;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::OnAssetChanged(const FAssetData & InAssetData, TSharedRef<IPropertyHandle> InHandle)
|
|
{
|
|
if (MaterialEditorInstance->bIsFunctionPreviewMaterial &&
|
|
MaterialEditorInstance->SourceFunction->GetMaterialFunctionUsage() != EMaterialFunctionUsage::Default)
|
|
{
|
|
UMaterialFunctionInterface* NewParent = Cast<UMaterialFunctionInterface>(InAssetData.GetAsset());
|
|
if (NewParent != nullptr)
|
|
{
|
|
MaterialEditorInstance->SourceFunction->SetParent(NewParent);
|
|
FPropertyChangedEvent ParentChanged = FPropertyChangedEvent(InHandle->GetProperty());
|
|
MaterialEditorInstance->PostEditChangeProperty(ParentChanged);
|
|
}
|
|
}
|
|
}
|
|
|
|
EVisibility FMaterialInstanceParameterDetails::ShouldShowMaterialRefractionSettings() const
|
|
{
|
|
return (MaterialEditorInstance->SourceInstance->GetMaterial()->bUsesDistortion && IsTranslucentBlendMode(MaterialEditorInstance->SourceInstance->GetBlendMode())) ? EVisibility::Visible : EVisibility::Collapsed;
|
|
}
|
|
|
|
EVisibility FMaterialInstanceParameterDetails::ShouldShowSubsurfaceProfile() const
|
|
{
|
|
FMaterialShadingModelField ShadingModels = MaterialEditorInstance->SourceInstance->GetShadingModels();
|
|
|
|
return UseSubsurfaceProfile(ShadingModels) ? EVisibility::Visible : EVisibility::Collapsed;
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::OnCopyParameterValues(int32 ParameterGroupIndex)
|
|
{
|
|
if (!MaterialEditorInstance || !MaterialEditorInstance->ParameterGroups.IsValidIndex(ParameterGroupIndex))
|
|
{
|
|
return;
|
|
}
|
|
FEditorParameterGroup& ParameterGroup = MaterialEditorInstance->ParameterGroups[ParameterGroupIndex];
|
|
|
|
TStringBuilder<4096> CombinedValue;
|
|
|
|
const int32 NumParams = ParameterGroup.Parameters.Num();
|
|
for (int32 ParamIdx = 0; ParamIdx < NumParams; ++ParamIdx)
|
|
{
|
|
UDEditorParameterValue* Parameter = ParameterGroup.Parameters[ParamIdx];
|
|
const FName ParamName = Parameter->ParameterInfo.Name;
|
|
|
|
const TCHAR* Prefix = (ParamIdx == 0) ? TEXT("") : TEXT(",");
|
|
|
|
// Include the value in the result entry only if the parameter is overridden.
|
|
const bool bOverride = FMaterialPropertyHelpers::IsOverriddenExpression(Parameter);
|
|
if (bOverride)
|
|
{
|
|
FProperty* ParameterValueProperty = Parameter->GetClass()->FindPropertyByName("ParameterValue");
|
|
if (ParameterValueProperty != nullptr)
|
|
{
|
|
FString ParameterValueString;
|
|
if (ParameterValueProperty->ExportText_InContainer(0, ParameterValueString, Parameter, Parameter, Parameter, PPF_Copy))
|
|
{
|
|
CombinedValue.Appendf(TEXT("%s%s.Override=True,%s.Value=\"%s\""),
|
|
Prefix,
|
|
*(ParamName.ToString()),
|
|
*(ParamName.ToString()),
|
|
*(ParameterValueString.ReplaceCharWithEscapedChar()));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CombinedValue.Appendf(TEXT("%s%s.Override=False"), Prefix, *(ParamName.ToString()));
|
|
}
|
|
}
|
|
|
|
if (CombinedValue.Len())
|
|
{
|
|
// Copy.
|
|
FPlatformApplicationMisc::ClipboardCopy(*CombinedValue);
|
|
}
|
|
}
|
|
|
|
bool FMaterialInstanceParameterDetails::CanCopyParameterValues(int32 ParameterGroupIndex)
|
|
{
|
|
return MaterialEditorInstance && MaterialEditorInstance->ParameterGroups.IsValidIndex(ParameterGroupIndex)
|
|
&& (MaterialEditorInstance->ParameterGroups[ParameterGroupIndex].Parameters.Num() > 0);
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::OnPasteParameterValues(int32 ParameterGroupIndex)
|
|
{
|
|
if (!MaterialEditorInstance || !MaterialEditorInstance->ParameterGroups.IsValidIndex(ParameterGroupIndex))
|
|
{
|
|
return;
|
|
}
|
|
|
|
FString ClipboardContent;
|
|
FPlatformApplicationMisc::ClipboardPaste(ClipboardContent);
|
|
if (!ClipboardContent.IsEmpty())
|
|
{
|
|
FScopedTransaction Transaction(LOCTEXT("PasteMaterialInstanceParameters", "Paste Material Instance Parameters"));
|
|
|
|
MaterialEditorInstance->Modify();
|
|
|
|
for (int32 ParamIdx = 0; ParamIdx < MaterialEditorInstance->ParameterGroups[ParameterGroupIndex].Parameters.Num(); ++ParamIdx)
|
|
{
|
|
UDEditorParameterValue* Parameter = MaterialEditorInstance->ParameterGroups[ParameterGroupIndex].Parameters[ParamIdx];
|
|
Parameter->Modify();
|
|
|
|
const FName ParamName = Parameter->ParameterInfo.Name;
|
|
|
|
const FString OverrideKey = FString::Printf(TEXT("%s.Override="), *(ParamName.ToString()));
|
|
bool bParsedOverride = false;
|
|
if (FParse::Bool(*ClipboardContent, *OverrideKey, bParsedOverride))
|
|
{
|
|
Parameter->bOverride = bParsedOverride;
|
|
if (bParsedOverride)
|
|
{
|
|
// Paste value.
|
|
const FString ValueKey = FString::Printf(TEXT("%s.Value="), *(ParamName.ToString()));
|
|
FString ParsedValueString;
|
|
if (FParse::Value(*ClipboardContent, *ValueKey, ParsedValueString))
|
|
{
|
|
ParsedValueString = ParsedValueString.ReplaceEscapedCharWithChar();
|
|
FProperty* ParameterValueProperty = Parameter->GetClass()->FindPropertyByName("ParameterValue");
|
|
if (ParameterValueProperty != nullptr)
|
|
{
|
|
void* ParameterValuePtr = ParameterValueProperty->ContainerPtrToValuePtr<void>(Parameter);
|
|
ParameterValueProperty->ImportText(*ParsedValueString, ParameterValuePtr, PPF_Copy, Parameter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MaterialEditorInstance->PostEditChange();
|
|
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
|
|
}
|
|
}
|
|
|
|
bool FMaterialInstanceParameterDetails::CanPasteParameterValues(int32 ParameterGroupIndex)
|
|
{
|
|
// First check the same criteria as copying.
|
|
if (!CanCopyParameterValues(ParameterGroupIndex))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Now see if there's anything to paste from the clipboard.
|
|
FString ClipboardContent;
|
|
FPlatformApplicationMisc::ClipboardPaste(ClipboardContent);
|
|
return !ClipboardContent.IsEmpty();
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::CreateLightmassOverrideWidgets(IDetailLayoutBuilder& DetailLayout)
|
|
{
|
|
IDetailCategoryBuilder& DetailCategory = DetailLayout.EditCategory(NAME_None);
|
|
|
|
static FName GroupName(TEXT("LightmassSettings"));
|
|
IDetailGroup& LightmassSettingsGroup = DetailCategory.AddGroup(GroupName, LOCTEXT("LightmassSettingsGroup", "Lightmass Settings"), false, false);
|
|
|
|
TAttribute<bool> IsOverrideCastShadowAsMaskedEnabled = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateLambda([this] { return (bool)MaterialEditorInstance->LightmassSettings.CastShadowAsMasked.bOverride; }));
|
|
TAttribute<bool> IsOverrideEmissiveBoostEnabled = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateLambda([this] { return (bool)MaterialEditorInstance->LightmassSettings.EmissiveBoost.bOverride; }));
|
|
TAttribute<bool> IsOverrideDiffuseBoostEnabled = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateLambda([this] { return (bool)MaterialEditorInstance->LightmassSettings.DiffuseBoost.bOverride; }));
|
|
TAttribute<bool> IsOverrideExportResolutionScaleEnabled = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateLambda([this] { return (bool)MaterialEditorInstance->LightmassSettings.ExportResolutionScale.bOverride; }));
|
|
|
|
TSharedRef<IPropertyHandle> LightmassSettings = DetailLayout.GetProperty("LightmassSettings");
|
|
TSharedPtr<IPropertyHandle> CastShadowAsMaskedProperty = LightmassSettings->GetChildHandle("CastShadowAsMasked");
|
|
TSharedPtr<IPropertyHandle> EmissiveBoostProperty = LightmassSettings->GetChildHandle("EmissiveBoost");
|
|
TSharedPtr<IPropertyHandle> DiffuseBoostProperty = LightmassSettings->GetChildHandle("DiffuseBoost");
|
|
TSharedPtr<IPropertyHandle> ExportResolutionScaleProperty = LightmassSettings->GetChildHandle("ExportResolutionScale");
|
|
|
|
|
|
FIsResetToDefaultVisible IsCastShadowAsMaskedPropertyResetVisible = FIsResetToDefaultVisible::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
return MaterialEditorInstance->Parent != nullptr ? MaterialEditorInstance->LightmassSettings.CastShadowAsMasked.ParameterValue != MaterialEditorInstance->Parent->GetCastShadowAsMasked() : false;
|
|
});
|
|
FResetToDefaultHandler ResetCastShadowAsMaskedPropertyHandler = FResetToDefaultHandler::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
if (MaterialEditorInstance->Parent != nullptr)
|
|
{
|
|
MaterialEditorInstance->LightmassSettings.CastShadowAsMasked.ParameterValue = MaterialEditorInstance->Parent->GetCastShadowAsMasked();
|
|
}
|
|
});
|
|
FResetToDefaultOverride ResetCastShadowAsMaskedPropertyOverride = FResetToDefaultOverride::Create(IsCastShadowAsMaskedPropertyResetVisible, ResetCastShadowAsMaskedPropertyHandler);
|
|
IDetailPropertyRow& CastShadowAsMaskedPropertyRow = LightmassSettingsGroup.AddPropertyRow(CastShadowAsMaskedProperty->GetChildHandle(0).ToSharedRef());
|
|
CastShadowAsMaskedPropertyRow
|
|
.DisplayName(CastShadowAsMaskedProperty->GetPropertyDisplayName())
|
|
.ToolTip(CastShadowAsMaskedProperty->GetToolTipText())
|
|
.EditCondition(IsOverrideCastShadowAsMaskedEnabled, FOnBooleanValueChanged::CreateLambda([this](bool NewValue) {
|
|
MaterialEditorInstance->LightmassSettings.CastShadowAsMasked.bOverride = (uint32)NewValue;
|
|
MaterialEditorInstance->PostEditChange();
|
|
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
|
|
}))
|
|
.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::IsOverriddenAndVisible, IsOverrideCastShadowAsMaskedEnabled)))
|
|
.OverrideResetToDefault(ResetCastShadowAsMaskedPropertyOverride);
|
|
|
|
FIsResetToDefaultVisible IsEmissiveBoostPropertyResetVisible = FIsResetToDefaultVisible::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
return MaterialEditorInstance->Parent != nullptr ? MaterialEditorInstance->LightmassSettings.EmissiveBoost.ParameterValue != MaterialEditorInstance->Parent->GetEmissiveBoost() : false;
|
|
});
|
|
FResetToDefaultHandler ResetEmissiveBoostPropertyHandler = FResetToDefaultHandler::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
if (MaterialEditorInstance->Parent != nullptr)
|
|
{
|
|
MaterialEditorInstance->LightmassSettings.EmissiveBoost.ParameterValue = MaterialEditorInstance->Parent->GetEmissiveBoost();
|
|
}
|
|
});
|
|
FResetToDefaultOverride ResetEmissiveBoostPropertyOverride = FResetToDefaultOverride::Create(IsEmissiveBoostPropertyResetVisible, ResetEmissiveBoostPropertyHandler);
|
|
IDetailPropertyRow& EmissiveBoostPropertyRow = LightmassSettingsGroup.AddPropertyRow(EmissiveBoostProperty->GetChildHandle(0).ToSharedRef());
|
|
EmissiveBoostPropertyRow
|
|
.DisplayName(EmissiveBoostProperty->GetPropertyDisplayName())
|
|
.ToolTip(EmissiveBoostProperty->GetToolTipText())
|
|
.EditCondition(IsOverrideEmissiveBoostEnabled, FOnBooleanValueChanged::CreateLambda([this](bool NewValue) {
|
|
MaterialEditorInstance->LightmassSettings.EmissiveBoost.bOverride = (uint32)NewValue;
|
|
MaterialEditorInstance->PostEditChange();
|
|
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
|
|
}))
|
|
.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::IsOverriddenAndVisible, IsOverrideEmissiveBoostEnabled)))
|
|
.OverrideResetToDefault(ResetEmissiveBoostPropertyOverride);
|
|
|
|
FIsResetToDefaultVisible IsDiffuseBoostPropertyResetVisible = FIsResetToDefaultVisible::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
return MaterialEditorInstance->Parent != nullptr ? MaterialEditorInstance->LightmassSettings.DiffuseBoost.ParameterValue != MaterialEditorInstance->Parent->GetDiffuseBoost() : false;
|
|
});
|
|
FResetToDefaultHandler ResetDiffuseBoostPropertyHandler = FResetToDefaultHandler::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
if (MaterialEditorInstance->Parent != nullptr)
|
|
{
|
|
MaterialEditorInstance->LightmassSettings.DiffuseBoost.ParameterValue = MaterialEditorInstance->Parent->GetDiffuseBoost();
|
|
}
|
|
});
|
|
FResetToDefaultOverride ResetDiffuseBoostPropertyOverride = FResetToDefaultOverride::Create(IsDiffuseBoostPropertyResetVisible, ResetDiffuseBoostPropertyHandler);
|
|
IDetailPropertyRow& DiffuseBoostPropertyRow = LightmassSettingsGroup.AddPropertyRow(DiffuseBoostProperty->GetChildHandle(0).ToSharedRef());
|
|
DiffuseBoostPropertyRow
|
|
.DisplayName(DiffuseBoostProperty->GetPropertyDisplayName())
|
|
.ToolTip(DiffuseBoostProperty->GetToolTipText())
|
|
.EditCondition(IsOverrideDiffuseBoostEnabled, FOnBooleanValueChanged::CreateLambda([this](bool NewValue) {
|
|
MaterialEditorInstance->LightmassSettings.DiffuseBoost.bOverride = (uint32)NewValue;
|
|
MaterialEditorInstance->PostEditChange();
|
|
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
|
|
}))
|
|
.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::IsOverriddenAndVisible, IsOverrideDiffuseBoostEnabled)))
|
|
.OverrideResetToDefault(ResetDiffuseBoostPropertyOverride);
|
|
|
|
FIsResetToDefaultVisible IsExportResolutionScalePropertyResetVisible = FIsResetToDefaultVisible::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
return MaterialEditorInstance->Parent != nullptr ? MaterialEditorInstance->LightmassSettings.ExportResolutionScale.ParameterValue != MaterialEditorInstance->Parent->GetDiffuseBoost() : false;
|
|
});
|
|
FResetToDefaultHandler ResetExportResolutionScalePropertyHandler = FResetToDefaultHandler::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
if (MaterialEditorInstance->Parent != nullptr)
|
|
{
|
|
MaterialEditorInstance->LightmassSettings.ExportResolutionScale.ParameterValue = MaterialEditorInstance->Parent->GetDiffuseBoost();
|
|
}
|
|
});
|
|
FResetToDefaultOverride ResetExportResolutionScalePropertyOverride = FResetToDefaultOverride::Create(IsExportResolutionScalePropertyResetVisible, ResetExportResolutionScalePropertyHandler);
|
|
IDetailPropertyRow& ExportResolutionScalePropertyRow = LightmassSettingsGroup.AddPropertyRow(ExportResolutionScaleProperty->GetChildHandle(0).ToSharedRef());
|
|
ExportResolutionScalePropertyRow
|
|
.DisplayName(ExportResolutionScaleProperty->GetPropertyDisplayName())
|
|
.ToolTip(ExportResolutionScaleProperty->GetToolTipText())
|
|
.EditCondition(IsOverrideExportResolutionScaleEnabled, FOnBooleanValueChanged::CreateLambda([this](bool NewValue) {
|
|
MaterialEditorInstance->LightmassSettings.ExportResolutionScale.bOverride = (uint32)NewValue;
|
|
MaterialEditorInstance->PostEditChange();
|
|
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
|
|
}))
|
|
.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::IsOverriddenAndVisible, IsOverrideExportResolutionScaleEnabled)))
|
|
.OverrideResetToDefault(ResetExportResolutionScalePropertyOverride);
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::CreateBasePropertyOverrideWidgets(IDetailLayoutBuilder& DetailLayout, IDetailGroup& MaterialPropertyOverrideGroup)
|
|
{
|
|
IDetailGroup& BasePropertyOverrideGroup = MaterialPropertyOverrideGroup;
|
|
|
|
TAttribute<bool> IsOverrideOpacityClipMaskValueEnabled = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::OverrideOpacityClipMaskValueEnabled));
|
|
TAttribute<bool> IsOverrideBlendModeEnabled = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::OverrideBlendModeEnabled));
|
|
TAttribute<bool> IsOverrideShadingModelEnabled = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::OverrideShadingModelEnabled));
|
|
TAttribute<bool> IsOverrideTwoSidedEnabled = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::OverrideTwoSidedEnabled));
|
|
TAttribute<bool> IsOverrideDitheredLODTransitionEnabled = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::OverrideDitheredLODTransitionEnabled));
|
|
TAttribute<bool> IsOverrideOutputTranslucentVelocityEnabled = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::OverrideOutputTranslucentVelocityEnabled));
|
|
|
|
TSharedRef<IPropertyHandle> BasePropertyOverridePropery = DetailLayout.GetProperty("BasePropertyOverrides");
|
|
TSharedPtr<IPropertyHandle> OpacityClipMaskValueProperty = BasePropertyOverridePropery->GetChildHandle("OpacityMaskClipValue");
|
|
TSharedPtr<IPropertyHandle> BlendModeProperty = BasePropertyOverridePropery->GetChildHandle("BlendMode");
|
|
TSharedPtr<IPropertyHandle> ShadingModelProperty = BasePropertyOverridePropery->GetChildHandle("ShadingModel");
|
|
TSharedPtr<IPropertyHandle> TwoSidedProperty = BasePropertyOverridePropery->GetChildHandle("TwoSided");
|
|
TSharedPtr<IPropertyHandle> DitheredLODTransitionProperty = BasePropertyOverridePropery->GetChildHandle("DitheredLODTransition");
|
|
TSharedPtr<IPropertyHandle> OutputTranslucentVelocityProperty = BasePropertyOverridePropery->GetChildHandle("bOutputTranslucentVelocity");
|
|
|
|
{
|
|
FIsResetToDefaultVisible IsOpacityClipMaskValuePropertyResetVisible = FIsResetToDefaultVisible::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
return MaterialEditorInstance->Parent != nullptr ? MaterialEditorInstance->BasePropertyOverrides.OpacityMaskClipValue != MaterialEditorInstance->Parent->GetOpacityMaskClipValue() : false;
|
|
});
|
|
FResetToDefaultHandler ResetOpacityClipMaskValuePropertyHandler = FResetToDefaultHandler::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
if (MaterialEditorInstance->Parent != nullptr)
|
|
{
|
|
MaterialEditorInstance->BasePropertyOverrides.OpacityMaskClipValue = MaterialEditorInstance->Parent->GetOpacityMaskClipValue();
|
|
}
|
|
});
|
|
FResetToDefaultOverride ResetOpacityClipMaskValuePropertyOverride = FResetToDefaultOverride::Create(IsOpacityClipMaskValuePropertyResetVisible, ResetOpacityClipMaskValuePropertyHandler);
|
|
IDetailPropertyRow& OpacityClipMaskValuePropertyRow = BasePropertyOverrideGroup.AddPropertyRow(OpacityClipMaskValueProperty.ToSharedRef());
|
|
OpacityClipMaskValuePropertyRow
|
|
.DisplayName(OpacityClipMaskValueProperty->GetPropertyDisplayName())
|
|
.ToolTip(OpacityClipMaskValueProperty->GetToolTipText())
|
|
.EditCondition(IsOverrideOpacityClipMaskValueEnabled, FOnBooleanValueChanged::CreateSP(this, &FMaterialInstanceParameterDetails::OnOverrideOpacityClipMaskValueChanged))
|
|
.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::IsOverriddenAndVisible, IsOverrideOpacityClipMaskValueEnabled)))
|
|
.OverrideResetToDefault(ResetOpacityClipMaskValuePropertyOverride);
|
|
}
|
|
{
|
|
FIsResetToDefaultVisible IsBlendModePropertyResetVisible = FIsResetToDefaultVisible::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
return MaterialEditorInstance->Parent != nullptr ? MaterialEditorInstance->BasePropertyOverrides.BlendMode != MaterialEditorInstance->Parent->GetBlendMode() : false;
|
|
});
|
|
FResetToDefaultHandler ResetBlendModePropertyHandler = FResetToDefaultHandler::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
if (MaterialEditorInstance->Parent != nullptr)
|
|
{
|
|
MaterialEditorInstance->BasePropertyOverrides.BlendMode = MaterialEditorInstance->Parent->GetBlendMode();
|
|
}
|
|
});
|
|
FResetToDefaultOverride ResetBlendModePropertyOverride = FResetToDefaultOverride::Create(IsBlendModePropertyResetVisible, ResetBlendModePropertyHandler);
|
|
IDetailPropertyRow& BlendModePropertyRow = BasePropertyOverrideGroup.AddPropertyRow(BlendModeProperty.ToSharedRef());
|
|
BlendModePropertyRow
|
|
.DisplayName(BlendModeProperty->GetPropertyDisplayName())
|
|
.ToolTip(BlendModeProperty->GetToolTipText())
|
|
.EditCondition(IsOverrideBlendModeEnabled, FOnBooleanValueChanged::CreateSP(this, &FMaterialInstanceParameterDetails::OnOverrideBlendModeChanged))
|
|
.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::IsOverriddenAndVisible, IsOverrideBlendModeEnabled)))
|
|
.OverrideResetToDefault(ResetBlendModePropertyOverride);
|
|
}
|
|
{
|
|
FIsResetToDefaultVisible IsShadingModelPropertyResetVisible = FIsResetToDefaultVisible::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
if (MaterialEditorInstance->Parent != nullptr)
|
|
{
|
|
if (MaterialEditorInstance->Parent->IsShadingModelFromMaterialExpression())
|
|
{
|
|
return MaterialEditorInstance->BasePropertyOverrides.ShadingModel != MSM_FromMaterialExpression;
|
|
}
|
|
else
|
|
{
|
|
return MaterialEditorInstance->BasePropertyOverrides.ShadingModel != MaterialEditorInstance->Parent->GetShadingModels().GetFirstShadingModel();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
});
|
|
FResetToDefaultHandler ResetShadingModelPropertyHandler = FResetToDefaultHandler::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
if (MaterialEditorInstance->Parent != nullptr)
|
|
{
|
|
if (MaterialEditorInstance->Parent->IsShadingModelFromMaterialExpression())
|
|
{
|
|
MaterialEditorInstance->BasePropertyOverrides.ShadingModel = MSM_FromMaterialExpression;
|
|
}
|
|
else
|
|
{
|
|
MaterialEditorInstance->BasePropertyOverrides.ShadingModel = MaterialEditorInstance->Parent->GetShadingModels().GetFirstShadingModel();
|
|
}
|
|
}
|
|
});
|
|
FResetToDefaultOverride ResetShadingModelPropertyOverride = FResetToDefaultOverride::Create(IsShadingModelPropertyResetVisible, ResetShadingModelPropertyHandler);
|
|
IDetailPropertyRow& ShadingModelPropertyRow = BasePropertyOverrideGroup.AddPropertyRow(ShadingModelProperty.ToSharedRef());
|
|
ShadingModelPropertyRow
|
|
.DisplayName(ShadingModelProperty->GetPropertyDisplayName())
|
|
.ToolTip(ShadingModelProperty->GetToolTipText())
|
|
.EditCondition(IsOverrideShadingModelEnabled, FOnBooleanValueChanged::CreateSP(this, &FMaterialInstanceParameterDetails::OnOverrideShadingModelChanged))
|
|
.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::IsOverriddenAndVisible, IsOverrideShadingModelEnabled)))
|
|
.OverrideResetToDefault(ResetShadingModelPropertyOverride);
|
|
}
|
|
{
|
|
FIsResetToDefaultVisible IsTwoSidedPropertyResetVisible = FIsResetToDefaultVisible::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
return MaterialEditorInstance->Parent != nullptr ? MaterialEditorInstance->BasePropertyOverrides.TwoSided != MaterialEditorInstance->Parent->IsTwoSided() : false;
|
|
});
|
|
FResetToDefaultHandler ResetTwoSidedValuePropertyHandler = FResetToDefaultHandler::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
if (MaterialEditorInstance->Parent != nullptr)
|
|
{
|
|
MaterialEditorInstance->BasePropertyOverrides.TwoSided = MaterialEditorInstance->Parent->IsTwoSided();
|
|
}
|
|
});
|
|
FResetToDefaultOverride ResetTwoSidedPropertyOverride = FResetToDefaultOverride::Create(IsTwoSidedPropertyResetVisible, ResetTwoSidedValuePropertyHandler);
|
|
IDetailPropertyRow& TwoSidedPropertyRow = BasePropertyOverrideGroup.AddPropertyRow(TwoSidedProperty.ToSharedRef());
|
|
TwoSidedPropertyRow
|
|
.DisplayName(TwoSidedProperty->GetPropertyDisplayName())
|
|
.ToolTip(TwoSidedProperty->GetToolTipText())
|
|
.EditCondition(IsOverrideTwoSidedEnabled, FOnBooleanValueChanged::CreateSP(this, &FMaterialInstanceParameterDetails::OnOverrideTwoSidedChanged))
|
|
.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::IsOverriddenAndVisible, IsOverrideTwoSidedEnabled)))
|
|
.OverrideResetToDefault(ResetTwoSidedPropertyOverride);
|
|
}
|
|
{
|
|
FIsResetToDefaultVisible IsDitheredLODTransitionPropertyResetVisible = FIsResetToDefaultVisible::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
return MaterialEditorInstance->Parent != nullptr ? MaterialEditorInstance->BasePropertyOverrides.DitheredLODTransition != MaterialEditorInstance->Parent->IsDitheredLODTransition() : false;
|
|
});
|
|
FResetToDefaultHandler ResetDitheredLODTransitionPropertyHandler = FResetToDefaultHandler::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
if (MaterialEditorInstance->Parent != nullptr)
|
|
{
|
|
MaterialEditorInstance->BasePropertyOverrides.DitheredLODTransition = MaterialEditorInstance->Parent->IsDitheredLODTransition();
|
|
}
|
|
});
|
|
FResetToDefaultOverride ResetDitheredLODTransitionPropertyOverride = FResetToDefaultOverride::Create(IsDitheredLODTransitionPropertyResetVisible, ResetDitheredLODTransitionPropertyHandler);
|
|
IDetailPropertyRow& DitheredLODTransitionPropertyRow = BasePropertyOverrideGroup.AddPropertyRow(DitheredLODTransitionProperty.ToSharedRef());
|
|
DitheredLODTransitionPropertyRow
|
|
.DisplayName(DitheredLODTransitionProperty->GetPropertyDisplayName())
|
|
.ToolTip(DitheredLODTransitionProperty->GetToolTipText())
|
|
.EditCondition(IsOverrideDitheredLODTransitionEnabled, FOnBooleanValueChanged::CreateSP(this, &FMaterialInstanceParameterDetails::OnOverrideDitheredLODTransitionChanged))
|
|
.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::IsOverriddenAndVisible, IsOverrideDitheredLODTransitionEnabled)))
|
|
.OverrideResetToDefault(ResetDitheredLODTransitionPropertyOverride);
|
|
}
|
|
{
|
|
FIsResetToDefaultVisible IsOutputTranslucentVelocityPropertyResetVisible = FIsResetToDefaultVisible::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
return MaterialEditorInstance->Parent != nullptr ? MaterialEditorInstance->BasePropertyOverrides.bOutputTranslucentVelocity != MaterialEditorInstance->Parent->IsTranslucencyWritingVelocity() : false;
|
|
});
|
|
FResetToDefaultHandler ResetOutputTranslucentVelocityPropertyHandler = FResetToDefaultHandler::CreateLambda([this](TSharedPtr<IPropertyHandle> InHandle) {
|
|
if (MaterialEditorInstance->Parent != nullptr)
|
|
{
|
|
MaterialEditorInstance->BasePropertyOverrides.bOutputTranslucentVelocity = MaterialEditorInstance->Parent->IsTranslucencyWritingVelocity();
|
|
}
|
|
});
|
|
FResetToDefaultOverride ResetOutputTranslucentVelocityPropertyOverride = FResetToDefaultOverride::Create(IsOutputTranslucentVelocityPropertyResetVisible, ResetOutputTranslucentVelocityPropertyHandler);
|
|
IDetailPropertyRow& OutputTranslucentVelocityPropertyRow = BasePropertyOverrideGroup.AddPropertyRow(OutputTranslucentVelocityProperty.ToSharedRef());
|
|
OutputTranslucentVelocityPropertyRow
|
|
.DisplayName(OutputTranslucentVelocityProperty->GetPropertyDisplayName())
|
|
.ToolTip(OutputTranslucentVelocityProperty->GetToolTipText())
|
|
.EditCondition(IsOverrideOutputTranslucentVelocityEnabled, FOnBooleanValueChanged::CreateSP(this, &FMaterialInstanceParameterDetails::OnOverrideOutputTranslucentVelocityChanged))
|
|
.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateSP(this, &FMaterialInstanceParameterDetails::IsOverriddenAndVisible, IsOverrideOutputTranslucentVelocityEnabled)))
|
|
.OverrideResetToDefault(ResetOutputTranslucentVelocityPropertyOverride);
|
|
}
|
|
}
|
|
|
|
EVisibility FMaterialInstanceParameterDetails::IsOverriddenAndVisible(TAttribute<bool> IsOverridden) const
|
|
{
|
|
bool bShouldBeVisible = true;
|
|
if (MaterialEditorInstance->bShowOnlyOverrides)
|
|
{
|
|
bShouldBeVisible = IsOverridden.Get();
|
|
}
|
|
return bShouldBeVisible ? EVisibility::Visible : EVisibility::Collapsed;
|
|
}
|
|
|
|
bool FMaterialInstanceParameterDetails::OverrideOpacityClipMaskValueEnabled() const
|
|
{
|
|
return MaterialEditorInstance->BasePropertyOverrides.bOverride_OpacityMaskClipValue;
|
|
}
|
|
|
|
bool FMaterialInstanceParameterDetails::OverrideBlendModeEnabled() const
|
|
{
|
|
return MaterialEditorInstance->BasePropertyOverrides.bOverride_BlendMode;
|
|
}
|
|
|
|
bool FMaterialInstanceParameterDetails::OverrideShadingModelEnabled() const
|
|
{
|
|
return MaterialEditorInstance->BasePropertyOverrides.bOverride_ShadingModel;
|
|
}
|
|
|
|
bool FMaterialInstanceParameterDetails::OverrideTwoSidedEnabled() const
|
|
{
|
|
return MaterialEditorInstance->BasePropertyOverrides.bOverride_TwoSided;
|
|
}
|
|
|
|
bool FMaterialInstanceParameterDetails::OverrideDitheredLODTransitionEnabled() const
|
|
{
|
|
return MaterialEditorInstance->BasePropertyOverrides.bOverride_DitheredLODTransition;
|
|
}
|
|
|
|
bool FMaterialInstanceParameterDetails::OverrideOutputTranslucentVelocityEnabled() const
|
|
{
|
|
return MaterialEditorInstance->BasePropertyOverrides.bOverride_OutputTranslucentVelocity;
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::OnOverrideOpacityClipMaskValueChanged(bool NewValue)
|
|
{
|
|
MaterialEditorInstance->BasePropertyOverrides.bOverride_OpacityMaskClipValue = NewValue;
|
|
MaterialEditorInstance->PostEditChange();
|
|
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::OnOverrideBlendModeChanged(bool NewValue)
|
|
{
|
|
MaterialEditorInstance->BasePropertyOverrides.bOverride_BlendMode = NewValue;
|
|
MaterialEditorInstance->PostEditChange();
|
|
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::OnOverrideShadingModelChanged(bool NewValue)
|
|
{
|
|
MaterialEditorInstance->BasePropertyOverrides.bOverride_ShadingModel = NewValue;
|
|
MaterialEditorInstance->PostEditChange();
|
|
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::OnOverrideTwoSidedChanged(bool NewValue)
|
|
{
|
|
MaterialEditorInstance->BasePropertyOverrides.bOverride_TwoSided = NewValue;
|
|
MaterialEditorInstance->PostEditChange();
|
|
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::OnOverrideDitheredLODTransitionChanged(bool NewValue)
|
|
{
|
|
MaterialEditorInstance->BasePropertyOverrides.bOverride_DitheredLODTransition = NewValue;
|
|
MaterialEditorInstance->PostEditChange();
|
|
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
|
|
}
|
|
|
|
void FMaterialInstanceParameterDetails::OnOverrideOutputTranslucentVelocityChanged(bool NewValue)
|
|
{
|
|
MaterialEditorInstance->BasePropertyOverrides.bOverride_OutputTranslucentVelocity = NewValue;
|
|
MaterialEditorInstance->PostEditChange();
|
|
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|
|
|