在UE的PCG系统运行中,博主总结主要包括三个东西:设置、执行者、数据。

设置:派生自UPCGSettings或UPCGSettingsInterface的类型,存在于类型系统可以让用户在编辑器面板上编辑该类型,在PCG图表内则是以节点的形式存在,主要用于控制参数设置、引脚连接、以及创建对应执行者对象的工作。

执行者:派生自IPCGElement的类型,不存在于UE类型系统。在执行者执行时通常获取上一个执行者处理完的数据,并根据读取Settings中的配置进行数据处理并输出。执行者可以是单线程的,可以是多线程的,可以是按数量切片多线程的方式等等。

数据:派生自UPCGSpatialDat的类型,表示实际数据类的基类,在执行者与执行者之间被处理和传递。其中很多节点都是围绕着点操作,UPCGPointData是最为常用的数据类型。

Contents

数据

这是PCG系统中的类型枚举,来自PCG的类型C++代码

UENUM(meta = (Bitflags))
enum class EPCGDataType : uint32
{
    None = 0 UMETA(Hidden),
    Point = 1 << 1,

    Spline = 1 << 2,
    LandscapeSpline = 1 << 3,
    PolyLine = Spline | LandscapeSpline UMETA(DisplayName = "Curve"),

    Landscape = 1 << 4,
    Texture = 1 << 5,
    RenderTarget = 1 << 6,
    BaseTexture = Texture | RenderTarget UMETA(Hidden),
    Surface = Landscape | BaseTexture,

    Volume = 1 << 7,
    Primitive = 1 << 8,

    /** Simple concrete data. */
    Concrete = Point | PolyLine | Surface | Volume | Primitive,

    /** Boolean operations like union, difference, intersection. */
    Composite = 1 << 9 UMETA(Hidden),

    /** Combinations of concrete data and/or boolean operations. */
    Spatial = Composite | Concrete,

    Param = 1 << 27 UMETA(DisplayName = "Attribute Set"),

    // Combination of Param and Point, necessary for named-based serialization of enums.
    PointOrParam = Point | Param,

    Settings = 1 << 28 UMETA(Hidden),
    Other = 1 << 29,
    Any = (1 << 30) - 1
};

Spatial

这些类型里可以看到一个非常常用的类型Concrete,经常出现在图表节点的引脚上,博主认为中文可以翻译为形状,有Point、PolyLine(Curve)、Surface、Volume等子类型。这些子类型都用有着实际的数据。

Spatial包括了Composite和Concrete类型,Concrete中都是储存各自子类型的实际数据,Union和Different这类可以处理任意Concrete子类型的类型则为Composite(意为Concrete的任意组合 所以实际引脚类型为Spatial)。

Spatial类型对应着UPCGSpatialData基类,拥有着MetaData。MetaData是一种可以储存自定义整形、浮点、向量等Attribute的结构,可以利用这些额外的自定义数据去扩展子类型的固定结构达到计算目的。

Point

Point对应的类为UPCGPointData,UPCGPointData内储存了点数据列表,同时可以使用上述提到基类UPCGSpatialData中的MetaData为Point增加额外的自定义数据。如果此处类比Houdini,那么就相当于Point拥有固定的P、N、v属性,其他的attr都是存放在MetaData中。

Param (AttributeSet)

Param对应类为UPCGParamData,在图表里也称为AttributeSet。虽然并不继承Spatial,但和Spatial一样拥有着MetaData。MetaData有着可以储存很多自定义Attribute的功能,而Param或者叫AttributeSet的主要功能就是仅储存MetaData,这样就能不需要其他Spatial结构自定义一组数据出来。就像一个随意增删修改字段的excel数据表格。

Point与AttributeSet

在类型枚举中可以看到PointOrParam = Point | Param这种复合类型。这两个类型有两点相近的特征:最为常用的数据类型和都拥有MetaData的能力。这也就导致两钟类型可以较为容易的转换和同时处理,例如AttributeFilter与AttributeNoise等节点。

Surface

主要用于在某个类型的Surface上采样,Surface对应着UPCGSurfaceData类,这个类只是个基类,具体是由LandscapeData、WorldRayHitData、TextureData等派生类具体实现。

设置

派生自UPCGSettings或UPCGSettingsInterface的类型。

Settings中需要重写的几个函数

CreateElement:返回对应的IPCGElement派生对象

GetDefaultNodeName:返回节点名字,PCG图表节点上的名字就是在这里获取

GetType:返回节点类型

InputPinProperties/OutputPinProperties:Pin口的名字与可接受的结构类型。

执行者

执行者派生自IPCGElement的类型,一般情况下一个节点功能就是对应编写一个Settings与一个Element。执行将分为多个阶段,分别是:

UENUM()
enum class EPCGExecutionPhase : uint8
{
        NotExecuted = 0,
        PrepareData,
        Execute,
        PostExecute,
        Done
};

FPCGGraphExecutor::Execute对各个IPCGElement对象执行Execute。在IPCGElement::Execute内部使用了一个循环的状态机来执行不同阶段的函数:

bool IPCGElement::Execute(FPCGContext* Context) const
{
    while (Context->CurrentPhase != EPCGExecutionPhase::Done)
    {
        //PreExecute (NotExecuted阶段)
        //PrepareDataInternal  (PrepareData阶段)
        //ExecuteInternal  (Execute阶段)
        //PostExecute  (PostExecute阶段)
    }
}

循环执行直到某个阶段函数将当前阶段变量设置为Done。在四个阶段函数PreExecute、PrepareDataInternal、ExecuteInternal、PostExecute,其中PreExecute和PostExecute不可被用户重写,所以用户只需要重写PrepareDataInternal和ExecuteInternal就可以了。

PreExecute:用户不可重写,主要判断该节点是否被禁用而跳过计算,正常情况下将会把阶段设置为PrepareData,跳过情况设置为Done。

PrepareDataInternal:用户可以重写。如果返回true,当前阶段将会被设置为Execute。

ExecuteInternal:用户可以重写,如果返回true,当前阶段将会被设置为PostExecute。

PostExecute:用户不可重写,收尾相关工作,执行后当前阶段将被设置为Done,然后执行完毕。

多线程顶点执行器

类FPCGPointOperationElementBase是一个简化的、时间切片的点处理器,只需要关心输入点与输出点。一个非常好的参考例子就是FPCGBoundsModifier。