vault backup: 2024-10-12 17:19:45
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
# MaterialControlFlow
|
||||
|
||||
- **功能描述:** 标识该UMaterialExpression为一个控制流节点,当前在材质蓝图右键菜单中隐藏。
|
||||
- **使用位置:** UCLASS
|
||||
- **引擎模块:** Material
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** UMaterialExpression子类
|
||||
- **常用程度:** ★
|
||||
|
||||
标识该UMaterialExpression为一个控制流节点,当前在材质蓝图右键菜单中隐藏。
|
||||
|
||||
一般是在IfThenElse,ForLoop这种节点上,当前引擎实现还未完善,因此该功能禁用。
|
||||
|
||||
## 源码例子:
|
||||
|
||||
```cpp
|
||||
UCLASS(collapsecategories, hidecategories=Object, MinimalAPI)
|
||||
class UMaterialExpressionIf : public UMaterialExpression
|
||||
{}
|
||||
|
||||
UCLASS(collapsecategories, hidecategories = Object, MinimalAPI, meta=(MaterialControlFlow))
|
||||
class UMaterialExpressionIfThenElse : public UMaterialExpression
|
||||
{}
|
||||
```
|
||||
|
||||
## 测试效果:
|
||||
|
||||
可以找到If节点,但是无法调用IfThenElse节点。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
在遍历所有可用FMaterialExpression的时候,如果有MaterialControlFlow则略过。当前引擎下AllowMaterialControlFlow一直未false,未实现。
|
||||
|
||||
```cpp
|
||||
|
||||
// r.MaterialEnableControlFlow is removed and the feature is forced disabled as how control flow should be
|
||||
// implemented in the material editor is still under discussion.
|
||||
inline bool AllowMaterialControlFlow()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void MaterialExpressionClasses::InitMaterialExpressionClasses()
|
||||
{
|
||||
static const auto CVarMaterialEnableNewHLSLGenerator = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MaterialEnableNewHLSLGenerator"));
|
||||
const bool bEnableControlFlow = AllowMaterialControlFlow();
|
||||
const bool bEnableNewHLSLGenerator = CVarMaterialEnableNewHLSLGenerator->GetValueOnAnyThread() != 0;
|
||||
|
||||
for( TObjectIterator<UClass> It ; It ; ++It )
|
||||
{
|
||||
if( Class->IsChildOf(UMaterialExpression::StaticClass()) )
|
||||
{
|
||||
// Hide node types related to control flow, unless it's enabled
|
||||
if (!bEnableControlFlow && Class->HasMetaData("MaterialControlFlow"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!bEnableNewHLSLGenerator && Class->HasMetaData("MaterialNewHLSLGenerator"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Hide node types that are tagged private
|
||||
if(Class->HasMetaData(TEXT("Private")))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
AllExpressionClasses.Add(MaterialExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
Binary file not shown.
After Width: | Height: | Size: 104 KiB |
@@ -0,0 +1,76 @@
|
||||
# MaterialNewHLSLGenerator
|
||||
|
||||
- **功能描述:** 标识该UMaterialExpression为采用新HLSL生成器的节点,当前在材质蓝图右键菜单中隐藏。
|
||||
- **使用位置:** UCLASS
|
||||
- **引擎模块:** Material
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** UMaterialExpression子类
|
||||
- **常用程度:** ★
|
||||
|
||||
标识该UMaterialExpression为采用新HLSL生成器的节点,当前在材质蓝图右键菜单中隐藏。
|
||||
|
||||
## 源码例子:
|
||||
|
||||
```cpp
|
||||
|
||||
UCLASS(MinimalAPI, meta = (MaterialNewHLSLGenerator))
|
||||
class UMaterialExpressionLess : public UMaterialExpressionBinaryOp
|
||||
{
|
||||
GENERATED_UCLASS_BODY()
|
||||
#if WITH_EDITOR
|
||||
virtual UE::HLSLTree::EOperation GetBinaryOp() const override { return UE::HLSLTree::EOperation::Less; }
|
||||
#endif // WITH_EDITOR
|
||||
};
|
||||
```
|
||||
|
||||
## 测试效果:
|
||||
|
||||
材质蓝图里无法调用Less。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
在遍历所有可用FMaterialExpression的时候,如果有MaterialNewHLSLGenerator则略过。当前引擎下r.MaterialEnableNewHLSLGenerator是只读的,且实现未完全。
|
||||
|
||||
```cpp
|
||||
static TAutoConsoleVariable<int32> CVarMaterialEnableNewHLSLGenerator(
|
||||
TEXT("r.MaterialEnableNewHLSLGenerator"),
|
||||
0,
|
||||
TEXT("Enables the new (WIP) material HLSL generator.\n")
|
||||
TEXT("0 - Don't allow\n")
|
||||
TEXT("1 - Allow if enabled by material\n")
|
||||
TEXT("2 - Force all materials to use new generator\n"),
|
||||
ECVF_RenderThreadSafe | ECVF_ReadOnly);
|
||||
|
||||
void MaterialExpressionClasses::InitMaterialExpressionClasses()
|
||||
{
|
||||
static const auto CVarMaterialEnableNewHLSLGenerator = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MaterialEnableNewHLSLGenerator"));
|
||||
const bool bEnableControlFlow = AllowMaterialControlFlow();
|
||||
const bool bEnableNewHLSLGenerator = CVarMaterialEnableNewHLSLGenerator->GetValueOnAnyThread() != 0;
|
||||
|
||||
for( TObjectIterator<UClass> It ; It ; ++It )
|
||||
{
|
||||
if( Class->IsChildOf(UMaterialExpression::StaticClass()) )
|
||||
{
|
||||
// Hide node types related to control flow, unless it's enabled
|
||||
if (!bEnableControlFlow && Class->HasMetaData("MaterialControlFlow"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!bEnableNewHLSLGenerator && Class->HasMetaData("MaterialNewHLSLGenerator"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Hide node types that are tagged private
|
||||
if(Class->HasMetaData(TEXT("Private")))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
AllExpressionClasses.Add(MaterialExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
@@ -0,0 +1,73 @@
|
||||
# MaterialParameterCollectionFunction
|
||||
|
||||
- **功能描述:** 指定该函数是用于操作UMaterialParameterCollection,从而支持ParameterName的提取和验证
|
||||
- **使用位置:** UFUNCTION
|
||||
- **引擎模块:** Material
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** 带有UMaterialParameterCollection参数的函数
|
||||
- **常用程度:** ★★★
|
||||
|
||||
指定该函数是用于操作UMaterialParameterCollection,从而支持ParameterName的提取和验证。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
|
||||
UCLASS(Blueprintable, BlueprintType)
|
||||
class INSIDER_API UMyFunction_Material :public UBlueprintFunctionLibrary
|
||||
{
|
||||
public:
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UFUNCTION(BlueprintCallable, meta=(WorldContext="WorldContextObject", MaterialParameterCollectionFunction))
|
||||
static void MySetScalarParameterValue(UObject* WorldContextObject, UMaterialParameterCollection* Collection, FName ParameterName, float ParameterValue);
|
||||
|
||||
UFUNCTION(BlueprintCallable, meta=(WorldContext="WorldContextObject"))
|
||||
static void MySetScalarParameterValue_NoError(UObject* WorldContextObject, UMaterialParameterCollection* Collection, FName ParameterName, float ParameterValue);
|
||||
};
|
||||
```
|
||||
|
||||
## 蓝图中效果:
|
||||
|
||||
引擎自带的UKismetMaterialLibrary::SetScalarParameterValue和我们自己手动编写的MySetScalarParameterValue,会触发材质参数集合的蓝图节点验证检测。如果没有指定ParameterName,则会产生编译错误。而没有MaterialParameterCollectionFunction标记的MySetScalarParameterValue_NoError函数版本则只是当作一个普通的函数一样,一是不会自动提取MPC中的Parameters集合来选择,二是没有ParameterName为空的错误验证。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
```cpp
|
||||
UBlueprintFunctionNodeSpawner* UBlueprintFunctionNodeSpawner::Create(UFunction const* const Function, UObject* Outer/* = nullptr*/)
|
||||
{
|
||||
bool const bIsMaterialParamCollectionFunc = Function->HasMetaData(FBlueprintMetadata::MD_MaterialParameterCollectionFunction);
|
||||
if (bIsMaterialParamCollectionFunc)
|
||||
{
|
||||
NodeClass = UK2Node_CallMaterialParameterCollectionFunction::StaticClass();
|
||||
}
|
||||
else
|
||||
{
|
||||
NodeClass = UK2Node_CallFunction::StaticClass();
|
||||
}
|
||||
}
|
||||
|
||||
TSharedPtr<SGraphNode> FNodeFactory::CreateNodeWidget(UEdGraphNode* InNode)
|
||||
{
|
||||
if (UK2Node_CallMaterialParameterCollectionFunction* CallFunctionNode = Cast<UK2Node_CallMaterialParameterCollectionFunction>(InNode))
|
||||
{
|
||||
return SNew(SGraphNodeCallParameterCollectionFunction, CallFunctionNode);
|
||||
}
|
||||
}
|
||||
TSharedPtr<SGraphPin> SGraphNodeCallParameterCollectionFunction::CreatePinWidget(UEdGraphPin* Pin) const
|
||||
{
|
||||
//提取MPC中参数列表等操作
|
||||
if (Collection)
|
||||
{
|
||||
// Populate the ParameterName pin combobox with valid options from the Collection
|
||||
const bool bVectorParameters = CallFunctionNode->FunctionReference.GetMemberName().ToString().Contains(TEXT("Vector"));
|
||||
Collection->GetParameterNames(NameList, bVectorParameters);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
MaterialParameterCollectionFunction这个标记的,会采用UK2Node_CallMaterialParameterCollectionFunction来验证材质函数的正确书写与否。同时UK2Node_CallMaterialParameterCollectionFunction这个蓝图节点也在引擎内部继续被识别以进一步定制化ParameterName的Pin节点。
|
||||
|
||||
引擎源码内采用MaterialParameterCollectionFunction标记的函数只有UKismetMaterialLibrary里的函数。
|
Binary file not shown.
After Width: | Height: | Size: 237 KiB |
@@ -0,0 +1,147 @@
|
||||
# OverridingInputProperty
|
||||
|
||||
- **功能描述:** 在UMaterialExpression中指定本float要覆盖的其他FExpressionInput 属性。
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Material
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** UMaterialExpression::float
|
||||
- **关联项:** [RequiredInput](../RequiredInput.md)
|
||||
- **常用程度:** ★★★
|
||||
|
||||
在UMaterialExpression中指定本float要覆盖的其他FExpressionInput 属性。
|
||||
|
||||
- 在材质表达式里有些属性,当用户没连接的时候,我们想提供一个默认值。这个时候这个Float属性的指就可以当作默认值。
|
||||
- 而当用户连接的时候,这个引脚又要变成一个正常的输入,因此得有另一个FExpressionInput 属性,所以才需要用OverridingInputProperty 指定另一个属性。
|
||||
- 被OverridingInputProperty 指定的FExpressionInput 属性一般是RequiredInput = "false",因为正常的逻辑是你都提供默认值了,那当然用户就不一定非得输入这个值了。当然也可以RequiredInput = "true",提醒用户这个引脚最好要有个输入,但如果真没有,也可以用默认值。
|
||||
- 输出节点上的很多BaseColor之类的引脚就是又RequiredInput又提供默认值的。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
在Compile函数中模仿源码给大家示范如何正确处理这种属性来获得值。大家也可以参照源码中别的例子来参考。
|
||||
|
||||
```cpp
|
||||
UCLASS()
|
||||
class UMyProperty_MyMaterialExpression : public UMaterialExpression
|
||||
{
|
||||
GENERATED_UCLASS_BODY()
|
||||
public:
|
||||
UPROPERTY()
|
||||
FExpressionInput MyInput_Default;
|
||||
|
||||
UPROPERTY(meta = (RequiredInput = "true"))
|
||||
FExpressionInput MyInput_Required;
|
||||
|
||||
UPROPERTY(meta = (RequiredInput = "false"))
|
||||
FExpressionInput MyInput_NotRequired;
|
||||
public:
|
||||
UPROPERTY(EditAnywhere, Category = OverridingInputProperty, meta = (RequiredInput = "false"))
|
||||
FExpressionInput MyAlpha;
|
||||
|
||||
/** only used if MyAlpha is not hooked up */
|
||||
UPROPERTY(EditAnywhere, Category = OverridingInputProperty, meta = (OverridingInputProperty = "MyAlpha"))
|
||||
float ConstAlpha = 1.f;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = OverridingInputProperty, meta = (RequiredInput = "true"))
|
||||
FExpressionInput MyAlpha2;
|
||||
|
||||
/** only used if MyAlpha is not hooked up */
|
||||
UPROPERTY(EditAnywhere, Category = OverridingInputProperty, meta = (OverridingInputProperty = "MyAlpha2"))
|
||||
float ConstAlpha2 = 1.f;
|
||||
public:
|
||||
|
||||
//~ Begin UMaterialExpression Interface
|
||||
#if WITH_EDITOR
|
||||
virtual int32 Compile(class FMaterialCompiler* Compiler, int32 OutputIndex) override
|
||||
{
|
||||
int32 IndexAlpha = MyAlpha.GetTracedInput().Expression ? MyAlpha.Compile(Compiler) : Compiler->Constant(ConstAlpha);
|
||||
return 0;
|
||||
}
|
||||
virtual void GetCaption(TArray<FString>& OutCaptions) const override;
|
||||
|
||||
virtual bool GenerateHLSLExpression(FMaterialHLSLGenerator& Generator, UE::HLSLTree::FScope& Scope, int32 OutputIndex, UE::HLSLTree::FExpression const*& OutExpression) const override;
|
||||
#endif
|
||||
//~ End UMaterialExpression Interface
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## 测试结果:
|
||||
|
||||
可见MyAlpha和MyAlpha2的右边都有个默认值,二者又因为RequiredInput的不同而一个灰色一个白色。
|
||||
|
||||
其他3个MyInput用来给大家对比。
|
||||
|
||||
右侧的材质最终输出表达式上的各个引脚更是有各种情况来让大家参考。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
其实也是根据Meta的标记,来改变引脚的可编辑状态以及输入框。
|
||||
|
||||
```cpp
|
||||
|
||||
bool UMaterialExpression::CanEditChange(const FProperty* InProperty) const
|
||||
{
|
||||
bool bIsEditable = Super::CanEditChange(InProperty);
|
||||
if (bIsEditable && InProperty != nullptr)
|
||||
{
|
||||
// Automatically set property as non-editable if it has OverridingInputProperty metadata
|
||||
// pointing to an FExpressionInput property which is hooked up as an input.
|
||||
//
|
||||
// e.g. in the below snippet, meta=(OverridingInputProperty = "A") indicates that ConstA will
|
||||
// be overridden by an FExpressionInput property named 'A' if one is connected, and will thereby
|
||||
// be set as non-editable.
|
||||
//
|
||||
// UPROPERTY(meta = (RequiredInput = "false", ToolTip = "Defaults to 'ConstA' if not specified"))
|
||||
// FExpressionInput A;
|
||||
//
|
||||
// UPROPERTY(EditAnywhere, Category = MaterialExpressionAdd, meta = (OverridingInputProperty = "A"))
|
||||
// float ConstA;
|
||||
//
|
||||
|
||||
static FName OverridingInputPropertyMetaData(TEXT("OverridingInputProperty"));
|
||||
|
||||
if (InProperty->HasMetaData(OverridingInputPropertyMetaData))
|
||||
{
|
||||
const FString& OverridingPropertyName = InProperty->GetMetaData(OverridingInputPropertyMetaData);
|
||||
|
||||
FStructProperty* StructProp = FindFProperty<FStructProperty>(GetClass(), *OverridingPropertyName);
|
||||
if (ensure(StructProp != nullptr))
|
||||
{
|
||||
static FName RequiredInputMetaData(TEXT("RequiredInput"));
|
||||
|
||||
// Must be a single FExpressionInput member, not an array, and must be tagged with metadata RequiredInput="false"
|
||||
if (ensure( StructProp->Struct->GetFName() == NAME_ExpressionInput &&
|
||||
StructProp->ArrayDim == 1 &&
|
||||
StructProp->HasMetaData(RequiredInputMetaData) &&
|
||||
!StructProp->GetBoolMetaData(RequiredInputMetaData)))
|
||||
{
|
||||
const FExpressionInput* Input = StructProp->ContainerPtrToValuePtr<FExpressionInput>(this);
|
||||
|
||||
if (Input->Expression != nullptr && Input->GetTracedInput().Expression != nullptr)
|
||||
{
|
||||
bIsEditable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bIsEditable)
|
||||
{
|
||||
// If the property has EditCondition metadata, then whether it's editable depends on the other EditCondition property
|
||||
const FString EditConditionPropertyName = InProperty->GetMetaData(TEXT("EditCondition"));
|
||||
if (!EditConditionPropertyName.IsEmpty())
|
||||
{
|
||||
FBoolProperty* EditConditionProperty = FindFProperty<FBoolProperty>(GetClass(), *EditConditionPropertyName);
|
||||
{
|
||||
bIsEditable = *EditConditionProperty->ContainerPtrToValuePtr<bool>(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bIsEditable;
|
||||
}
|
||||
|
||||
```
|
Binary file not shown.
After Width: | Height: | Size: 282 KiB |
@@ -0,0 +1,76 @@
|
||||
# Private
|
||||
|
||||
- **功能描述:** 标识该UMaterialExpression为私有节点,当前在材质蓝图右键菜单中隐藏。
|
||||
- **使用位置:** UCLASS
|
||||
- **引擎模块:** Material
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** UMaterialExpression子类
|
||||
- **常用程度:** ★
|
||||
|
||||
标识该UMaterialExpression为私有节点,当前在材质蓝图右键菜单中隐藏。
|
||||
|
||||
在MaterialX模块中使用,目前是把里面的Expression暂时先都隐藏起来。
|
||||
|
||||
## 源码例子:
|
||||
|
||||
```cpp
|
||||
UCLASS()
|
||||
class UMyMaterialExpression_NotPrivate : public UMaterialExpression
|
||||
{};
|
||||
|
||||
UCLASS(meta=(Private))
|
||||
class UMyMaterialExpression_Private : public UMaterialExpression
|
||||
{};
|
||||
```
|
||||
|
||||
## 测试效果:
|
||||
|
||||
材质蓝图里只能调用UMyMaterialExpression_NotPrivate 。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
在遍历所有可用FMaterialExpression的时候,如果有Private则略过。
|
||||
|
||||
```cpp
|
||||
static TAutoConsoleVariable<int32> CVarMaterialEnableNewHLSLGenerator(
|
||||
TEXT("r.MaterialEnableNewHLSLGenerator"),
|
||||
0,
|
||||
TEXT("Enables the new (WIP) material HLSL generator.\n")
|
||||
TEXT("0 - Don't allow\n")
|
||||
TEXT("1 - Allow if enabled by material\n")
|
||||
TEXT("2 - Force all materials to use new generator\n"),
|
||||
ECVF_RenderThreadSafe | ECVF_ReadOnly);
|
||||
|
||||
void MaterialExpressionClasses::InitMaterialExpressionClasses()
|
||||
{
|
||||
static const auto CVarMaterialEnableNewHLSLGenerator = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MaterialEnableNewHLSLGenerator"));
|
||||
const bool bEnableControlFlow = AllowMaterialControlFlow();
|
||||
const bool bEnableNewHLSLGenerator = CVarMaterialEnableNewHLSLGenerator->GetValueOnAnyThread() != 0;
|
||||
|
||||
for( TObjectIterator<UClass> It ; It ; ++It )
|
||||
{
|
||||
if( Class->IsChildOf(UMaterialExpression::StaticClass()) )
|
||||
{
|
||||
// Hide node types related to control flow, unless it's enabled
|
||||
if (!bEnableControlFlow && Class->HasMetaData("MaterialControlFlow"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!bEnableNewHLSLGenerator && Class->HasMetaData("MaterialNewHLSLGenerator"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Hide node types that are tagged private
|
||||
if(Class->HasMetaData(TEXT("Private")))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
AllExpressionClasses.Add(MaterialExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
Binary file not shown.
After Width: | Height: | Size: 47 KiB |
@@ -0,0 +1,83 @@
|
||||
# RequiredInput
|
||||
|
||||
- **功能描述:** 在UMaterialExpression中指定FExpressionInput属性是否要求输入,引脚显示白色或灰色。
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Material
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** UMaterialExpression::FExpressionInput
|
||||
- **关联项:** [OverridingInputProperty](OverridingInputProperty/OverridingInputProperty.md)
|
||||
|
||||
在UMaterialExpression中指定FExpressionInput属性是否要求输入,引脚显示白色或灰色。
|
||||
|
||||
一般都配合OverridingInputProperty使用。
|
||||
|
||||
代码和效果参见OverridingInputProperty
|
||||
|
||||
## 原理:
|
||||
|
||||
```cpp
|
||||
|
||||
bool UMaterialExpression::CanEditChange(const FProperty* InProperty) const
|
||||
{
|
||||
bool bIsEditable = Super::CanEditChange(InProperty);
|
||||
if (bIsEditable && InProperty != nullptr)
|
||||
{
|
||||
// Automatically set property as non-editable if it has OverridingInputProperty metadata
|
||||
// pointing to an FExpressionInput property which is hooked up as an input.
|
||||
//
|
||||
// e.g. in the below snippet, meta=(OverridingInputProperty = "A") indicates that ConstA will
|
||||
// be overridden by an FExpressionInput property named 'A' if one is connected, and will thereby
|
||||
// be set as non-editable.
|
||||
//
|
||||
// UPROPERTY(meta = (RequiredInput = "false", ToolTip = "Defaults to 'ConstA' if not specified"))
|
||||
// FExpressionInput A;
|
||||
//
|
||||
// UPROPERTY(EditAnywhere, Category = MaterialExpressionAdd, meta = (OverridingInputProperty = "A"))
|
||||
// float ConstA;
|
||||
//
|
||||
|
||||
static FName OverridingInputPropertyMetaData(TEXT("OverridingInputProperty"));
|
||||
|
||||
if (InProperty->HasMetaData(OverridingInputPropertyMetaData))
|
||||
{
|
||||
const FString& OverridingPropertyName = InProperty->GetMetaData(OverridingInputPropertyMetaData);
|
||||
|
||||
FStructProperty* StructProp = FindFProperty<FStructProperty>(GetClass(), *OverridingPropertyName);
|
||||
if (ensure(StructProp != nullptr))
|
||||
{
|
||||
static FName RequiredInputMetaData(TEXT("RequiredInput"));
|
||||
|
||||
// Must be a single FExpressionInput member, not an array, and must be tagged with metadata RequiredInput="false"
|
||||
if (ensure( StructProp->Struct->GetFName() == NAME_ExpressionInput &&
|
||||
StructProp->ArrayDim == 1 &&
|
||||
StructProp->HasMetaData(RequiredInputMetaData) &&
|
||||
!StructProp->GetBoolMetaData(RequiredInputMetaData)))
|
||||
{
|
||||
const FExpressionInput* Input = StructProp->ContainerPtrToValuePtr<FExpressionInput>(this);
|
||||
|
||||
if (Input->Expression != nullptr && Input->GetTracedInput().Expression != nullptr)
|
||||
{
|
||||
bIsEditable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bIsEditable)
|
||||
{
|
||||
// If the property has EditCondition metadata, then whether it's editable depends on the other EditCondition property
|
||||
const FString EditConditionPropertyName = InProperty->GetMetaData(TEXT("EditCondition"));
|
||||
if (!EditConditionPropertyName.IsEmpty())
|
||||
{
|
||||
FBoolProperty* EditConditionProperty = FindFProperty<FBoolProperty>(GetClass(), *EditConditionPropertyName);
|
||||
{
|
||||
bIsEditable = *EditConditionProperty->ContainerPtrToValuePtr<bool>(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bIsEditable;
|
||||
}
|
||||
|
||||
```
|
@@ -0,0 +1,102 @@
|
||||
# ShowAsInputPin
|
||||
|
||||
- **功能描述:** 使得UMaterialExpression里的一些基础类型属性变成材质节点上的引脚。
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Material
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** UMaterialExpression里的属性
|
||||
- **常用程度:** ★★★
|
||||
|
||||
使得UMaterialExpression里的一些基础类型属性变成材质节点上的引脚。
|
||||
|
||||
- 所谓基础类型,指的是float,FVector这种常用的类型。
|
||||
- 默认这些基础类型属性是不显示为引脚的。
|
||||
- ShowAsInputPin 值有两个选项,Primary可以直接显示出来,Advanced需要展开箭头后显示。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
|
||||
public:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PinTest)
|
||||
float MyFloat;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PinTest, meta = (ShowAsInputPin = "Primary"))
|
||||
float MyFloat_Primary;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PinTest, meta = (ShowAsInputPin = "Advanced"))
|
||||
float MyFloat_Advanced;
|
||||
```
|
||||
|
||||
## 测试结果:
|
||||
|
||||
可见MyFloat没有显示在节点上。
|
||||
|
||||
MyFloat_Primary显示在节点上。
|
||||
|
||||
MyFloat_Advanced需要展开箭头后才显示出来。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
遍历UMaterialExpression里的属性,根据含有ShowAsInputPin 的类型来生成引脚。
|
||||
|
||||
```cpp
|
||||
TArray<FProperty*> UMaterialExpression::GetPropertyInputs() const
|
||||
{
|
||||
TArray<FProperty*> PropertyInputs;
|
||||
|
||||
static FName OverridingInputPropertyMetaData(TEXT("OverridingInputProperty"));
|
||||
static FName ShowAsInputPinMetaData(TEXT("ShowAsInputPin"));
|
||||
for (TFieldIterator<FProperty> InputIt(GetClass(), EFieldIteratorFlags::IncludeSuper, EFieldIteratorFlags::ExcludeDeprecated); InputIt; ++InputIt)
|
||||
{
|
||||
bool bCreateInput = false;
|
||||
FProperty* Property = *InputIt;
|
||||
// Don't create an expression input if the property is already associated with one explicitly declared
|
||||
bool bOverridingInputProperty = Property->HasMetaData(OverridingInputPropertyMetaData);
|
||||
// It needs to have the 'EditAnywhere' specifier
|
||||
const bool bEditAnywhere = Property->HasAnyPropertyFlags(CPF_Edit);
|
||||
// It needs to be marked with a valid pin category meta data
|
||||
const FString ShowAsInputPin = Property->GetMetaData(ShowAsInputPinMetaData);
|
||||
const bool bShowAsInputPin = ShowAsInputPin == TEXT("Primary") || ShowAsInputPin == TEXT("Advanced");
|
||||
|
||||
if (!bOverridingInputProperty && bEditAnywhere && bShowAsInputPin)
|
||||
{
|
||||
// Check if the property type fits within the allowed widget types
|
||||
FFieldClass* PropertyClass = Property->GetClass();
|
||||
if (PropertyClass == FFloatProperty::StaticClass()
|
||||
|| PropertyClass == FDoubleProperty::StaticClass()
|
||||
|| PropertyClass == FIntProperty::StaticClass()
|
||||
|| PropertyClass == FUInt32Property::StaticClass()
|
||||
|| PropertyClass == FByteProperty::StaticClass()
|
||||
|| PropertyClass == FBoolProperty::StaticClass()
|
||||
)
|
||||
{
|
||||
bCreateInput = true;
|
||||
}
|
||||
else if (PropertyClass == FStructProperty::StaticClass())
|
||||
{
|
||||
FStructProperty* StructProperty = CastField<FStructProperty>(Property);
|
||||
UScriptStruct* Struct = StructProperty->Struct;
|
||||
if (Struct == TBaseStructure<FLinearColor>::Get()
|
||||
|| Struct == TBaseStructure<FVector4>::Get()
|
||||
|| Struct == TVariantStructure<FVector4d>::Get()
|
||||
|| Struct == TBaseStructure<FVector>::Get()
|
||||
|| Struct == TVariantStructure<FVector3f>::Get()
|
||||
|| Struct == TBaseStructure<FVector2D>::Get()
|
||||
)
|
||||
{
|
||||
bCreateInput = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bCreateInput)
|
||||
{
|
||||
PropertyInputs.Add(Property);
|
||||
}
|
||||
}
|
||||
|
||||
return PropertyInputs;
|
||||
}
|
||||
```
|
Binary file not shown.
After Width: | Height: | Size: 215 KiB |
Reference in New Issue
Block a user