UPCGBlueprintElement
是PCGGraph中自定义节点的基类,但官方目前还没有给出详细的文档,所以从源代码里找点答案。
文章目录
- 可覆盖函数(Override Functions)
- Excute 和 Excute with Context
- Loop Body函数和Loop函数
- Point Loop Body和PointLoop
- Variable Loop Body和VariableLoop
- Nested Loop Body和NestedLoop
- Iteration Loop Body和IterationLoop
可覆盖函数(Override Functions)
UPCGBlueprintElement是PCGGraph中所有自定义节点的基类,有如下几个可供蓝图覆盖的函数:
- Excute
- Excute with Context
- Iteration Loop Body
- Point Loop Body
- Variable Loop Body
- Nested Loop Body
- Node Color Override
- Node Title Override
- Node Type Override
其中 Excute
、Excute with Context
、NodeTitleOverride
、NodeColorOverride
、NodeTypeOverride
是覆盖后被自动触发的;而剩余的几个“Loop Body函数”则需要在蓝图中显示调用对应的“Loop函数”才可以执行循环,比如:要调用PointLoop
才可以执行Point Loop Body
Excute 和 Excute with Context
这两个函数可以理解为自定义节点的“主函数”,区别就是一个有PCGContext
输入另一个没有,ExecuteWithContext
会调用Execute
Excute
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "PCG|Execution")
void Execute(const FPCGDataCollection& Input, FPCGDataCollection& Output);
Excute with Context
UFUNCTION(BlueprintNativeEvent, Category = "PCG|Execution")
void ExecuteWithContext(UPARAM(ref)FPCGContext& InContext, const FPCGDataCollection& Input, FPCGDataCollection& Output);
void UPCGBlueprintElement::ExecuteWithContext_Implementation(FPCGContext& InContext, const FPCGDataCollection& Input, FPCGDataCollection& Output)
{
Execute(Input, Output);
}
其实还有个C++ 函数ExecuteInternal
,Excute with Context
是由它调用的。
virtual bool ExecuteInternal(FPCGContext* Context) const override;
/** Finally, execute the actual blueprint */
Context->BlueprintElementInstance->ExecuteWithContext(*Context, Context->InputData, Context->OutputData);
Loop Body函数和Loop函数
Loop Body函数都是在Loop函数中定义的lambda表达式调用的。
Point Loop Body
、Nested Loop Body
、Iteration Loop Body
通过FPCGAsync::AsyncPointProcessing
调用;Variable Loop Body
通过FPCGAsync::AsyncMultiPointProcessing
调用- 上述节点中的各种Data参数都是
PCGPointData
类型,需要的话可以在调用Loop函数的时候传入,它们会直接传入Loop Body函数
Point Loop Body和PointLoop
Point Loop Body
需要通过PointLoop
执行循环
Point Loop Body
PointLoop
FPCGAsync::AsyncPointProcessing(&InContext, InPoints.Num(), OutPoints, [this, &InContext, InData, OutData, &InPoints](int32 Index, FPCGPoint& OutPoint)
{
return PointLoopBody(InContext, InData, InPoints[Index], OutPoint, OutData->Metadata);
});
Variable Loop Body和VariableLoop
Variable Loop Body
需要通过VariableLoop
执行循环
VariableLoop
FPCGAsync::AsyncMultiPointProcessing(&InContext, InPoints.Num(), OutPoints, [this, &InContext, InData, OutData, &InPoints](int32 Index)
{
return VariableLoopBody(InContext, InData, InPoints[Index], OutData->Metadata);
});
}
FPCGAsync::AsyncPointProcessing
和FPCGAsync::AsyncMultiPointProcessing
都是异步的,它们的区别就在于处理输入:输出为1:1还是1:N的循环。Point Loop Body
和VariableLoopBody
,前者输入一个point返回一个point;后者输入一个point可以返回一个point的数组。比如:如果你想把一个point看作一块地基,想在它的垂直上方再生成一串点作为楼层,然后把这些点返回,那么你就需要用到VariableLoopBody
。
Nested Loop Body和NestedLoop
Nested Loop Body
需要通过NestedLoop
执行循环
关键代码如下,但使用情景没想明白。
NestedLoop
const TArray<FPCGPoint>& InOuterPoints = InOuterData->GetPoints();
const TArray<FPCGPoint>& InInnerPoints = InInnerData->GetPoints();
TArray<FPCGPoint>& OutPoints = OutData->GetMutablePoints();
FPCGAsync::AsyncPointProcessing(&InContext, InOuterPoints.Num() * InInnerPoints.Num(), OutPoints, [this, &InContext, InOuterData, InInnerData, OutData, &InOuterPoints, &InInnerPoints](int32 Index, FPCGPoint& OutPoint)
{
return NestedLoopBody(InContext, InOuterData, InInnerData, InOuterPoints[Index / InInnerPoints.Num()], InInnerPoints[Index % InInnerPoints.Num()], OutPoint, OutData->Metadata);
});
Iteration Loop Body和IterationLoop
Iteration Loop Body
需要通过IterationLoop
执行循环
和Point Loop Body
一样,但它会提供一个NumIterations
用于指定迭代次数
IterationLoop
FPCGAsync::AsyncPointProcessing(&InContext, NumIterations, OutPoints, [this, &InContext, InA, InB, OutData](int32 Index, FPCGPoint& OutPoint)
{
return IterationLoopBody(InContext, Index, InA, InB, OutPoint, OutData->Metadata);
});