虚幻引擎程序化资源生成框架PCG 之 UPCGBlueprintElement源码笔记(一)

虚幻引擎程序化资源生成框架PCG 之 UPCGBlueprintElement源码笔记(一)

7 人赞同了该文章
UPCGBlueprintElement是PCGGraph中自定义节点的基类,但官方目前还没有给出详细的文档,所以从源代码里找点答案。


在这里插入图片描述


可覆盖函数(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

其中 ExcuteExcute with ContextNodeTitleOverrideNodeColorOverrideNodeTypeOverride是覆盖后被自动触发的;而剩余的几个“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++ 函数ExecuteInternalExcute 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 BodyNested Loop BodyIteration 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::AsyncPointProcessingFPCGAsync::AsyncMultiPointProcessing都是异步的,它们的区别就在于处理输入:输出为1:1还是1:N的循环。Point Loop BodyVariableLoopBody,前者输入一个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);
    });

编辑于 2023-07-17 05:36・IP 属地天津
写下你的评论...

爱害羞酷大笑发呆
还没有评论,发表第一个评论吧

文章被以下专栏收录

想来知乎工作?请发送邮件到 jobs@zhihu.com