【UE5】UE5 PCG

UE5.2预览版PCG工具:自定义 PCG Actor 和属性(05)-采样网格(06) - 哔哩哔哩 (bilibili.com)

注:本文部分使用UE5.4.2,部分使用UE5.3.1编写,部分内容上可能会有出入。

程序化内容生成框架-Procedural Content Generation Framework(PCG)是UE5.2开始加入的虚幻引擎的成化内容工具集,目前在UE5.4.2中主要由6个插件构成,分别是:

Procedural Content Generation Framework(PCG):核心插件,可视化脚本框架,用于在编辑器或运行时程序化地填充内容世界;

Procedural Content Generation Framework (PCG) External Data Interop:扩展插件,用于程序化内容生成框架的额外插件,与外部数据格式交互;

Procedural Content Generation Framework (PCG) Geometry Script Interop:扩展插件,提供PCG框架与UE的几何脚本进行交互的支持,几何脚本:支持通过蓝图或Python生成和编辑网格体;

Procedural Content Generation Framework PCG)Water Interop:扩展插件,提供PCG框架与UE的水体系统进行交互的支持;

PCG Biome Core:扩展插件,PCG生物群落创建工具;

PCG Biome Sample:扩展插件,PCG生物群落示例插件。

一般如果我们只需要PCG的基础功能时就只需要开启核心插件即可,当我开启PCG插件之后,在内容文件夹的右键菜单中就会多出一个PCG栏,下面有两个新的资产:PCG Graph和PCG Graph Instance:

PCG Grahp用于编写PCG逻辑,作用和蓝图中Event Graph、材质中的Material Graph、动画蓝图中Anim Graph等的作用是一样的。

PCG Graph Instance用于封装PCG Graph到实例,类似材质实例,但目前功能比较简单只提供封装。

我们的学习就从这里开始。

一、PCG框架

1.PCG流程

PCG的整个流程其实很简单就是:

graph LR;
A(采集点)-->B(生成点)-->C(处理点)-->D(在点上生成网格体)

整个PCG的处理逻辑就是围绕这四个过程来处理的。

2.PCG中的类

PCGGraph

PCG图表,存在于内容浏览器中的资产,提供编写PCG逻辑的图表,拖入场景中会生成对应的PCGVolume。

PCGGraphInstance

PCG图表实例,目前功能比较少,只是单纯的PCGGraph的封装。

PCGWorldActor

PCGWorldActor是一个PCG应用世界分区的辅助类,由PCG框架自动在应用了PCG的关卡中生成,PCGWorldActor为UE的内部类,不对蓝图公开继承,不可直接从关卡中删除,如果需要删除需要选中对应的PCGWorldActor点击Tools/PCG Framework/Deletes all PCG World Actors这个PCG框架准备的专用工具来删除。

PCGVolume

PCG体积,PCG资产在关卡中的存在形式,由BrushComponet和PCGComponent两个组件构成。

PCGComponent

Actor与PCG框架沟通的桥梁,在5.4中不止是PCGVolume,任何拥有PCGCompoent的Actor都可以通过这个组件与PCG框架通信,这样我们就可以创建自定义的PCG体积了。

PCGGenerationSource

PCGSetting

PCGPoint

PCGPoint结构体是PCG框架对点的描述,一个PCGPoint描述的就是一个点,包含了点的最基础的信息,如:Transform、Density、BoundsMin、BoundsMax、Color、Steepness、Seed、Metadata Entry等。

PCGPointData

封装PCG点数据的对象,对于不同的类型的点数据PCG都定义了封装对象,如:PCGCollisionShapeData、PCGDifferenceData、PCGLandscapeData、PCGPolyLineData、PCGPrimitiveData、PCGProjectionData、PCHRenderTargetData、PCGSPatialData、PCGSplineData、PCGSurfaceData、PCGTextureData、PCGVolumeData等。

PCGData

所有PCG点数据封装对象的父类。一个PCGData对象封装的就是一组点数据。

PCGTaggedData

PCGTaggedData是PCGData的封装,尽管PCGData封装了一组完整的点数据,但是在PCGBlueprintElement的输入中可以设置多个输入引脚,那么就需要一个东西去区分不同引脚的数,这个东西就是PCGTaggedData,PCGTaggedData将PCGData和一个名为Tags的Set、一个FName类型的Pin封装起来,以区分不同引脚的PCGData,其中Pin标注的就是引脚的名称,至于Tags的作用,暂时不知,源码中也没有什么提示。

PCGDataCollection

PCGDataCollection则又是PCGTaggedData的封装,这一层的封装主要是为了方便用于函数的输入输出,PCGDataCollection就是一个PCGTaggedData的数组。

PCGContext

PCGContext是用于存储PCG操作上下文的结构体,上下文就是程序执行时的执行环境和状态信息,在PCG的流程中可能点数据在一个节点输入到这个节点的输出,数据就会发生剧烈的变化,所以在编写节点时保存PCG执行的上下文就显得尤为重要。

PCGBlueprintElement

PCGBlueprintElement是PCG框架提供给我们编写自定义节点的工具,凡是继承自PCGBlueprintElement的Actor都可以被拖入PCGGraph中被Execute Blueprint封装作为一个节点的形式存在,PCGBlueprintElement提供给我们更强大的PCG数据处理能力,以便我们可以编写能够处理一些PCG框架提供的节点无法完成的工作的自定义节点。

打开PCGBlueprintElement蓝图编辑界面,界面和普通蓝图几乎没有区别(毕竟也是从Actor派生出来的),不同的只有三处Variables变量栏,Class Defaults类默认设置和Functions Overridable重载函数。

Variables

PCGBlueprintElement的变量和普通Actor不同的是,PCGBlueprintElement的变量被设置为Instance Editable(可编辑实例)时,变量会显示在节点的细节面板中,其实也没那么不同,不过是一个显示在节点实例的细节面板中,一个显示在关卡中Actor实例的细节面板中。

Class Defaults

PCGBlueprintElement的类默认设置中少了大量的Actor的类设置,而新增了两个独有的类设置,Settings和Asset Info。

  • Settings/Requires Game Thread:需要游戏线程,控制此类是否可以在非游戏线程中运行,默认启用;
  • Settings/Input & Output/Custom Input Pins和Custom Output Pins:为PCGBlueprintElement节点添加自定义输入输出引脚的设置,理论上可以添加无数个输入输出引脚,自定义引脚的详情可以参见第二章PCG节点第一小节输入输出,在5.4中多出了一个设置,Usage(用途),有三种类型,Normal普通的引脚,Loop和Feedback看提示是说和循环子图配合使用的,但是始终没试出效果,估计是为未来的功能添加的;
  • Settings/Input & Output/Has Default In和Out Pin:控制节点是否包含默认的输入输出引脚;
  • Settings/Advanced/Is Cacheable、Compute Full Data Crc、Dependency Parsing Depth:为可缓存、计算完成数据Crc、依赖性解析深度,这三个高级选项和PCG的缓存相关,是在追求更高的性能时才会使用的,大多数形况下不使用,并且PCG的缓存一直存在一些问题,大多数情况尽量不要去碰缓存;
  • Settings/Asset Info/Expose to Library:公开到库,如果勾选则此PCGBlueprintElement节点就会在PCG的节点库中出现;
  • Settings/Asset Info/Category:节点在PCG节点库中所处的分栏;
  • Settings/Asset Info/Description:节点在节点库中鼠标悬停时的提示文本。

Execute和ExecuteWithContext

Execute和ExecuteWithContext函数是PCG节点的主要执行入口,可以理解为编程中Main函数,节点的输入由此函数接收,节点的输出由此函数传递,在每次PCGGraph执行到此节点时函数会被执行一次。Execute是被隐藏了Context输入的ExecuteWithContext函数,ExecuteWithContext的执行优先级比Execute高,在同时重载了ExecuteWithContext和Execute时,只会执行ExecuteWithContext函数,而Execute函数不会执行。在Execute函数中如果也想要获取Context参数可以通过Get Context函数获取,Context是PCGBlueprintElement类最重要的变量,包含着整个节点执行的上下文内容,PCGBlueprintElement类中很多函数都需要Context的支持,比如常用的To Point Data With Context、Get Input Data等。

Is CacheableOverride

专门动态用于覆盖类默认设置中Is Cacheable选项的函数,只有一个Bool值输出。

PointLoopBody

用于遍历点数据的函数:

输入为PCGContext、PCGPointData、PCGPoint、PCGMetadata和Int64的循环次数索引,输出为PCGPoint的单点数据,其实输入只需要PCGContext和Int64的索引即可,其他的数据都可以从Context中获取,但是为了方便UE还是提供了PCGPointData和PCGPoint。Out Metadata是PointLoop函数中Optional Out Data的元数据。

PointLoopBody是点循环函数的实现而并不是调用,要调用这个函数需要使用PointLoop这个封装函数:

其中InData传入源PCGPointData,OptionalOutData传入的是需要承接返回点数据的PCGPointData对象,需要主要在蓝图中使用时要先构造PCGPointData对象,再传入,而不是单纯的创建一个变量传入,单纯创建一个变量,变量是一个空指针,传入后将不会生效。

IterationLoopBody

IterationLoopBody也是一个点循环函数,相对于PointLoopBody,InterationLoopBody类似ForLoop,而PointLoopBody类似ForEachLoop:

和PointLoopBody一样,IterationLoopBody使用IterationLoop调用:

其中Num Interations设置循环的次数,Optional A和Optional B是可选的PCGSpatialData类型参数,看源码的描述是用来初始化OutData的,当Optional A可用时使用Optional A输入来初始化OutData,当Optional B可用时,使用Optional B来初始化OutData,同时两个参数在InterationLoopBody的输入中分别对应In A,In B可以在循环体中使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//UE_5.4\Engine\Plugins\PCG\Source\PCG\Private\Elements\PCGExecuteBlueprint.cpp
void UPCGBlueprintElement::IterationLoop(FPCGContext& InContext, int64 NumIterations, UPCGPointData*& OutData, const UPCGSpatialData* InA, const UPCGSpatialData* InB, UPCGPointData* OptionalOutData) const
{
if (NumIterations < 0)
{
PCGE_LOG_C(Error, GraphAndLog, &InContext, FText::Format(LOCTEXT("InvalidIterationCount", "Invalid number of iterations ({0})"), NumIterations));
return;
}

if (OptionalOutData)
{
OutData = OptionalOutData;
}
else
{
const UPCGSpatialData* Owner = (InA ? InA : InB);
OutData = NewObject<UPCGPointData>();

if (Owner)
{
OutData->InitializeFromData(Owner);
}
}

TArray<FPCGPoint>& OutPoints = OutData->GetMutablePoints();

FPCGAsync::AsyncPointProcessing(&InContext, NumIterations, OutPoints, [this, &InContext, InA, InB, OutData](int32 Index, FPCGPoint& OutPoint)
{
return IterationLoopBody(InContext, Index, InA, InB, OutPoint, OutData->Metadata);
});
}

NestedLoopBody

嵌套点循环体,一个双层嵌套循环函数,就是这种形式:

1
2
3
4
5
6
7
for(i=0;i<n;++1)
{
for(j=0;j<m;++j)
{

}
}

Outer Data是外层循环点数据,Inner Data是内层循环点数据,循环过程就是先循环Outer Data的数据,索引没增加一次,完整遍历一次Inner Data的数据。

由NestedLoop函数调用。

VariableLoopBody

变量点循环体,遍历过程和PointLoopBody一样,完整遍历一组点数据,区别在于,PointLoopBody输入一个点数据则返回一个点数据,而VariableLoopBody输入一个点数据返回一组点数据。

适用于由一个点发散成多个点的循环过程,由VariableLoop调用。

NodeColorOverride

设置PCGBlueprintElement在PCG图表中的颜色。

NodeTitleOverride

设置PCGBlueprintElement在PCG图表中的名字。

NodeTypeOverride

设置PCGBlueprintElement在PCG图表中的节点类型,修改的是节点的分类不影响实际功能。

ApplyPreconfiguredSettings

源码注释是说用来设置节点的预配置项的,但是没有找到任何资料,暂时没尝试出来怎么用。

二、PCG节点

PCG Graph是PCG可视化脚本框架的核心,通过创建PCG Graph资产我们可以像编写材质逻辑一样编写PCG生成逻辑,和材质系统拥有众多的独立材质蓝图节点一样,PCG Graph也拥有众多的独立PCG蓝图节点,PCG的程序化内容生成逻辑就是由这些节点组合而成。

参考文档:虚幻引擎中的程序化内容生成框架节点参考 | 虚幻引擎 5.4 文档 | Epic Developer Community (epicgames.com)

1.输入输出

输入输出节点Input和Output是PCGGraph资产中默认且必须存在的两个节点,作用类似函数的输入输出。

Input节点用于接收PCG框架在Level中采集到的PCG框架所需要的数据,Output节点则是将自定义的PCG逻辑的计算结果输出到PCG框架体系中。

与UE5.3不同,在UE5.4中,Input节点只默认提供Spatial类型的In引脚而不再直接提供各类其他输入数据的引脚了,而是改由开发者自己在Input节点的Details/Settings/Pins中自主添加引脚,PCG框架会根据Input的引脚数量和类型自动分配输入数据。

属性

  • Settings/Input/Custom Pins:一个自定义引脚数组,可以定义自定义输入输出引脚;

  • Settings/Input/Custom Pins/Index[n]/Label:引脚的标签,即名称;

  • Settings/Input/Custom Pins/Index[n]/Allowed Types:引脚接收的或返回的数据类型,支持:

    类型 说明
    Point 点集,最常用的引脚类型之一
    Spline 样条线
    Landscape Spline 地形样条线
    Curve 曲线
    Landscape 地形数据
    Texture 纹理数据
    Render Target 渲染目标,也是纹理数据的一种
    Surface 表面数据
    Volume 体积数据
    Primitive 图元数据
    Concrete 具体
    Spatial 空间数据
    Attribute Set 属性集,可以是只有单个属性的属性,也可以是多个属性的集合
    Other 其他,没懂什么鬼
    Any 泛型引脚
  • Settings/Input/Custom Pins/Index[n]/Allow Multiple Data:是否允许接收多个数据,如果勾选,则自定义引脚可以接收单分支的多批数据集,或是不同分支的多个数据集,输入后全都合并成单个分支的多批数据集;

  • Settings/Input/Custom Pins/Index[n]/Allow Multiple Connections:是否允许引脚接受多个连接,配合Allow Multiple Data使用;

  • Settings/Input/Custom Pins/Index[n]/Advanced Pin:高级引脚,勾选后,在引脚未被使用时,会自动被折叠,不勾选则始终显示;

  • Settings/Input/Custom Pins/Index[n]/Tooltip:引脚的鼠标悬浮提示。

2.Blueprint(蓝图)

Execute Blueprint

执行蓝图,需要指定一个PCGBlueprintElement蓝图类作为执行模板,否则执行蓝图就是一个空节点,并且PCG框架会提示节点确实蓝图,但不会报错。PCGBlueprintElement是PCG框架中有一个类,这个蓝图类是专门用来给执行蓝图使用的,我们可以创建自定义的PCGBlueprintElement蓝图编写自定义处理逻辑,只要是继承自PCGBlueprintElement的蓝图就都可以在执行蓝图节点的Template/Blueprint Element Type中指定,除此之外,UE官方还在/All/EngineData/Plugins/PCG/BP_Elements/Deprecated下提供了大量的预制PCGBlueprintElement蓝图,这里介绍一些比较常用的预制蓝图。

ProjectPointsOnLandscape

将点集附着到Landscape上,接收两个输入Landscape接收表面数据,PointsToProject接收目标点集,输出附着到表面的点集;

ScaleByDensity

密度转大小缩放,接收点集使用点的密度属性设置到点的缩放属性,输出设置缩放后的点集;

DistanceToDensity

根据点到指定坐标的距离来设置点的密度。

  • Density Mode:密度模式,设置计算密度的算法;
  • Reference Point:参考点,要指定的中心点的坐标;
  • Compute Distance 2D:是否只计算2D的平面距离,即忽略Z轴,默认是计算三维空间距离;
  • Gradient Scale:梯度大小,设置过度边界的大小;
  • Gradient Offset:梯度偏移,设置过度边界离中心点的距离,边界以内的点密度被设置为0,边界以外的点密度被设置为1,边界中的点密度由0到1过渡;
  • Clamp Output:使点的密度不限制在0-1的范围内;
  • Negate Clamped Output:反转点的密度,在Clamp Output为True时生效。

HeightToDensity

根据高度修改点的密度。

  • Defualt/Gradient Offset:梯度偏移,可以理解为高度阈值,高度高于阈值的点密度会被设置为大于0的值,高度小于阈值的点密度则被设置为0;
  • Defualt/Gradient Scale:梯度缩放,可以理解为密度的扩散范围,高度高于阈值的点会根据扩散范围密度逐渐由0增加到1,超过扩散范围以上的点密度则全为1;
  • Defualt/Density Mode:设置点密度的方式。

3.Control Flow(控制流程)

Branch(分支)

接收一个输入点集,根据bool变量控制点击由OutputA输出或是OutputB输出。通过这个节点可以很方便的控制点击根据条件做不同的变化。

  • Settings/Output to B:点集是否从B输出端口输出,默认为false,即由A端口输出。

Select(选择)

select节点与branch节点相反,接收两个输入,根据bool变量控制使用那个输入作为输出。

  • Settings/Use Input B:是否选择B输入端口作为输出,默认为false,即由A输入端口作为输出。

4.调试

5.Density(密度)

Density Remap(密度重估)

可以将指定输入范围的密度重新映射到指定的范围输出,如将0-1的密度范围的点重新在0.5-1的区间内映射,那么输出的点的密度就全部在0-5-1之间了。

6.Filter(过滤器)

Density Filter(密度过滤器)

接收点数据,通过点的密度值筛选符合要求的点数据输出。

属性

  • Settings/Lower Bound:设置密度下边界;
  • Settings/Upper Bound:设置密度上边界;
  • Invert Filter:反向筛选。

Attribute Filter(属性过滤器)

属性过滤器属于过滤器中的高级节点,点过滤器、密度过滤器、自动调整等都是基于属性过滤器的。属性过滤器有两种模式,使用常量阈值和不使用常量阈值,使用常量阈值模式时接收点集或属性集,将数据筛选出符合阈值要求的和不符合阈值要求的两个集合,分别从Inside Filter引脚和Outside Filter引脚输出;如果使用不使用常量阈值模式,则接收两个输入,In引脚接收点集或属性集,Filter引脚接收泛型数据,将数据筛选出符合阈值要求且符合Filter要求的数据和其他的数据两部分,符合要求的数据由Outside Filter引脚输出,其他的数据由Inside Filter引脚输出。第一个中模式比较好理解,第二种模式我们可以使用一个例子来理解:

这里属性过滤器使用的运算符是>,目标属性和阈值属性都是密度,使用了空间查询。目标属性和阈值属性可以使用不同的属性,只要属性值类型相同就可以用来做对比筛选。

这一段逻辑的结果就是在Spline01这条样条线的点集中筛选出和Spline03这条样条线中的点集有相交且密度大于相交点的点集,由Outside Filter输出,和除此之外的其他的点集,由Inside Filter输出。

Inside Filter的输出点集:

Outside Filter输出的点集:

这样看可能不直观,动图来看可能更直观:

属性

  • Settings/Operator:运算符,设置属性比较的运算符;
  • Settings/Target Attribute:目标属性,In引脚接收的集合要取出来用来比较的属性;
  • Settings/Use Constant Threshold:使用常量阈值,控制属性过滤器要使用比较模式,在不使用常量阈值时属性过滤器会多出一个Filter引脚;
  • Settings/Threshold Attribute:阈值属性,Filter引脚接收的集合要取出来用来比较的属性,不使用阈值常量模式可用;
  • Settings/Use Spatial Query:使用空间查询,如果阅值数据为点数据,其将对阅值数据中的输入点进行采样。对于空间数据始终为true。
  • Settings/Type:要比较的数据类型,在使用常量阈值模式时可用;
  • Settings/xx Value:要比较的值,xx根据类型名字会变化,在使用常量阈值模式时可用。

Point Filter(点过滤器)

点过滤器是属性过滤器的别名,二者是同一个节点,只是目标属性的默认选择的属性不一样。

Point Filter Range(点过滤范围)

可以设置筛选最小值和最大值的点过滤。

Filter - Any(过滤器-任意)

数据过滤,接收数据筛选出目标类型的数据输出,一般用于点数据到空间数据,或空间数据到点数据的转换。

7.泛型

8.辅助

9.层级化生成

10.Metadata(元数据)

Attribute Noise和Density Noise(属性噪声)

输入点集使用Input Suorce指定的点的属性通过Mode指定的运算方式随机计算出运算结果设置到Output Target指定的点的属性上,随机值在Noise Min和Noise Max之间,输出设置了新属性值的点集。

Attribute Noise和Density Noise是同一个节点的两个不同的名称,只是默认的输入源不同。

属性

  • Settings/Input Source:输入源,参加运算的点的属性;
  • Settings/Output Target:输出目标,计算结果要赋予的点的属性;
  • Settings/Mode:模式,运算方式;
  • Settings/Noise Min和Max:随机噪声的最小值和最大值;
  • Settings/Invert Source:反转源,新的运算结果=1-运算结果;
  • Settings/Clamp Result:限制结果,限制结果在0-1之间;
  • Settings/Seed:随机计算的随机种子。

Get Attribute From Point Index(从索引获取点的属性)

接收点集,通过属性获取单个点的属性,输出单点的属性和这个点。

属性

  • Settings/Input Source:要接收的属性;
  • Settings/Index:点的索引;
  • Settings/Output Attribute Name:要输出的属性别名。

Create Attribute(创建属性)

创建一个图表私有的属性,一般用于图表中统一设置参数。

Copy Attribute(拷贝属性)

从点集原有的属性中拷贝一份值用新的名称作为新属性添加到点集属性列表中。一般配合Attribute Partition和Loop节点使用。

Attribute Partition(属性拆分)

按照指定的属性将点拆分为多批,相同的值被分为一批,属性分批主要是配合Loop节点使用,点被分批之后Loop就可以按批循环执行循环操作了。

比如我们要遍历每一个点,那么就需要这样:

使用Copy Attribute拷贝一个Index属性添加到属性列表,再使用Attribute Partition按Index属性拆分,这样每一个点就是一批,然后传入Loop,这样在Loop子图里就可以按Index遍历每一个点,当然Loop子图输出的点也是分批的,如果需要合并成一批则需要使用Merge节点合批。

这是UE5.3的操作,应该是Attribute Partition节点有bug,不能直接使用点集原有的属性,所以需要使用Copy Attribute来添加一个自定义属性,UE5.4中就没有那么麻烦,可以直接使用点集原有的属性。

Attribute Select(选择属性)

接收一个空间数据,输出找到的第一个符合选择要求的点和点的属性。可以点击Input Source后的加号选择点的固有属性,也可以直接输入属性名称选择自定义属性。

Math:xx(属性数学运算)

属性的数学运算,目前支持如下运算:

运算服 说明
Abs 计算”绝对值”数学运算的值。将输入属性值转换为正值,并将结果写入属性。
Add 计算”加法”数学运算的值。取两个输入值,加起来,并将结果写入属性。
Ceil 计算”向上取整”数学运算的值。取一个输入值,向上舍入到下一个整数。
Clamp 计算”限制”数学运算的值。取输入值,将其约束到特定范围。
Clamp Max 提供”限制”数学运算的最大值。
Clamp Min 提供”限制”数学运算的最小值。
Divide 计算”除法”数学运算的值。取两个输入,将第一个输入除以第二个输入,并将结果写入属性。
Floor 计算”向下取整”数学运算的值。取一个输入值,向下舍入到最接近的整数,并将结果写入属性。
Frac 计算小数数学运算的值。取一个输入值,返回该值的小数部分。例如,对于输入值X,结果是X减去X的向下取整值。输出值的范围从0到1,含0,不含1。
Lerp 计算”线性插值”数学运算的值。此表达式将在两个点之间画一条线,使用第三个”比率”值确定该线上某个点的值。 接着将此值写入属性。
Max 计算对属性的”最大值”数学运算的值,并将结果写入属性。此运算取两个输入值,并输出两者中较大者。
Min 计算对属性的”最小值”数学运算的值,并将结果写入属性。 此运算取两个输入值,并输出两者中较小者。
Modulo 计算”取模”数学运算的值。取两个输入值,将第一个值除以第二个值。接着返回余数,并将其作为属性写入。
Multiply 计算”乘法”数学运算的值。取两个输入值,相乘,并将结果写入属性。
One Minus 计算对属性的”一减”数学运算的值,并将结果写入属性。此表达式将取一个输入值X,输出1-X,并将结果作为属性写入。
Pow 计算”幂”数学运算的值。此表达式将取两个值:底数和指数。它计算底数值的指数次幂,并将结果作为属性输出。
Round 计算”四舍五入”数学运算的值,并将结果写入属性。此表达式将取一个输入值,并将其舍入到最接近的整数。
Set 将输出属性设置为提供的属性的值。
Sign 计算”符号”数学运算的值,并将结果写入属性。对一个输入值求值,指示它是正数、负数还是刚好为零。如果输入为负数,此节点输出-1。如果输入刚好为0,此节点输出0。如果输入为正数,此节点输出1。
Sqrt 计算对输入的”平方根”数学运算的值,并将结果写入属性。
Subtract 计算”减法”数学运算的值。此表达式将取两个输入,从第一个输入减去第二个输入。
Truncate 计算”截断”数学运算的值,并将结果写入属性。此表达式将截断一个值,即舍弃小数部分,留下整数。例如,值1.4截断为1。

11.Param(参数)

Get Actor Property(获取Actor属性)

获取Actor属性节点用于PCGGraph在对外公开属性时获取外部属性到PCGGraph。

那么PCGGraph如何公开属性到外部呢?

最常用的方案是通过自定义Actor封装PCGComponent,然后使用Actor的变量来对外公开。

首先我们创建一个Actor蓝图,然后为Actor添加PCG组件,在PCG组件的Details/Instance/Graph中指定与组件绑定的PCGGraph,然后在Actor中创建变量Points并设置可编辑实例,即将眼睛点开,然后在对应的PCGGraph的获取Actor属性节点的Actor Selector Settins/Actor Filter设置为Self,Settings/Property Name设置要为Points,即获取的变量的名称,这样节点就获取到了Points变量的值,将节点连接到需要用到的引脚即可使用了。

当一个PCGGraph使用了获取Actor属性节点之后,就不能随意再将这个PCGGraph丢入场景中使用了,因为可能导致获取Actor属性节点获取属性失败,从而导致节点报错。

目前PCG的更新依旧有一些bug,即当Actor的属性设置都正确以后,获取Actor属性节点的报错并没有消失,但却不影响使用,应该是节点更新的bug,关闭项目重启报错就消失了。

属性

  • Actor Selector Settings/Actor Filter:Actor过滤器,用来过滤要搜索的变量的Actor,可以是Slef(与此PCGGraph绑定的PCGComponent的拥有者Actor,如果启用的世界分区,可以是源Actor也可以是分区生成的Actor)、Parent(与此PCGGraph绑定的PCGComponent的拥有者Actor作为Actor组件挂载的父Actor)、Root(与此PCGGraph绑定的PCGComponent的拥有者Actor所在的挂载层级中的顶层Actor)、All World Actors(通过标签查找到的世界中的所有的Actor)、Original(源PCG Actor,而非分区生成的Actor);
  • Actor Selector Settings/Include Children:是否考虑搜索过滤出的Actor的子Actor;如果勾选可以通过类型或者标签来所搜Child Actor Component绑定的子Actor中的变量;当勾选了此选项后,节点会忽略此Actor中的同名变量,而使用子Actor中的变量;
  • Settings/Select Component:作用和Include Children差不多,勾选后可以通过类型或标签来搜索Actor的组件中的变量;
  • Settings/Property Name:要查询属性的名称,要查询的属性必须是勾选了可编辑实例的,否则会报“属性存在但不可见”;
  • Settings/Force Object and Struct Extraction:这个属性暂没探索出有什么作用,按照提示是“如果属性是元数据支持的结构体/Object,打开此选项可强制提取此属性中包含的所有(兼容)属性。如果元数据不支持,则自动设为true。目前只支持直接子属性(不支持更深的)”;
  • Settings/Output Attribute Name:这个属性暂没探索出有什么作用,按照提示是“属性名称将默认为空,但可以使用此名称重载。使用@SourceName来使用属性名称(仅在不提取时有效)”;
  • Settings/Always Requery Actors:如果这为true,PCG将永远不会把这个元素放入缓存,并且总是会尝试重新查询Actor并从中读取最新属性;
  • Settings/Track Actors Only Within Bounds:如果勾选此项,在组件边界之外找到Actor将不会触发刷新。目前只对编辑器中的标签有效。

获取Actor中的结构体变量

获取Actor中的结构体变量的方式和直接获取Actor中普通变量的方式一样,但要求结构体中的变量名称和要设置的属性的名称及类型完全一致,无法匹配的变量会被忽略,注意属性的名称和节点显示的名称可能不一致,查看属性的准确名称的方式是鼠标悬停在属性引脚上查看,如:

PCG会自动通过名称和类型来匹配对应的属性:

当然也可以将结构体变量连接到Overrides引脚,PCG会自动匹配属性输入。

12.Point Ops(点运算)

Transform Points(变换点)

点的Transform变换,接收采样结果进行点在Transform维度上的运算,输出运算后的采样结果。

属性

  • Settings/Apply to Attribute:
  • Settings/Attribute Name:
  • Settings/Offset Min和Offset Max:控制点变换过程中的位置变换的最小和最大值;
  • Settings/Absolute Offset:对于位置变换使用基于自身坐标的相对变换或是基于世界坐标的绝对变换;
  • Settings/Rotation Min和Rotation Max:控制点变换过程中的旋转变换的最小值和最大值;
  • Settings/Absolute Rotation:对于旋转变换使用基于自身坐标的相对变换或是基于世界坐标的绝对变换;
  • Settings/Scale Min和Scale Max:控制点变换过程中的缩放变换的最小值和最大值;
  • Settings/Absolute Scale:对于缩放变换使用基于自身坐标的相对变换或是基于世界坐标的绝对变换;
  • Settings/Uniform Scale:勾选了统一缩放后缩放值将以X值为主,更改YZ的值无法影响到缩放,不勾选则XYZ的值可以任意更改并分别应用到各自的缩放方向上;
  • Settings/Recompute Seed:作用说是使用新位置为每个点重新计算随机数种子,但是没有试具体有什么作用;
  • Seed:点变换节点的随机数种子;

Bounds Modifier(边界修改器)

边界修改器用于修改点的边界属性,在处理点与点、点与面相交时很有用。

属性

  • Settings/Mode:修改边界使用的模式,有Set(设置)、Intersect(相交)、Include(包含)、Translate(平移)、Scale(缩放)五个模式,五种模式只是算法不同最终的目的都是设置边界,一般直接使用Scale模式比较直观;
  • Settings/Bounds Min和Max:设置边界的最大值与最小值;
  • Settings/Affect Steepness:是否影响点的陡度;
  • Settings/Steepness:设置点陡度,算法是乘法,使用Steepness值乘以点的陡度得出来的值来设置点的陡度;

Self Pruning(自动调整)

输入点集剔除边界有重叠的点,输出剔除后的点集。

属性

  • Settings/Pruning Type:修剪类型,剔除规则;
  • Settings/Comparison Source:比较源,剔除时用于点与点之间作比较的属性;
  • Settings/Radius Similarity Factor:半径相似系数,考虑2个点“相等”的相似度系数,举例而言,如果一个点的平方长度为10,系数为0.25,则7.5到12.5之间的所有点都将被视为“相同”。
  • Settings/Randomized Pruning:随机化修剪,针对通过半径相似系数被认为相同的点是否启用随机修剪;

13.Sampler(采样器)

Surface Sampler(表面采样器)

表面采样器,接收Landscape地形的表面数据,根据对应的设置参数输出采样结果,应用采样结果的点均会附着在Landscape表面,我们启用节点按D启用调试可以看到所有应用了采样结果的点。

图中从黑到白的方块就是PCG根据采样生成的点,点的颜色黑灰白代表着点的密度,密度是点的一个属性,是一个0-1的随机值,1表示白色,0表示黑色。我们选中表面采样器节点在右键菜单中勾选Inspect(检查)或者直接按快捷键A,可以启动检查,然后在PCGGraph中的Debug Object视图可以看到一个列有场景中所有PCGGraph对象的列表,选中其中一个就可以查看整个PCGGraph输入和输出的所有的点的信息了

属性

  • Settings/Points Per Squared Meter:每平方米的点,故名思意,在UE单位中每平方米要随机生成多少个点,注意需要配合Point Extents使用,如果点的方位很大,每平方米生成一个点就已经把PCG体积占满了,那么无论Points Per Squared Meter设置的多大都不会再生成新的点;

  • Settings/Point Extents:点的方位,一个点占用的空间大小,会影响Points Per Squared Meter值下点的密度;

  • Settings/Looseness:点的松散度,值越大生成的点越稀疏,点也越少;

  • Setttings/Unbounded:解除PCG体积的边界限制,如果勾选点将不再局限再PCG体积中,而是在所有输入的Landscape数据中生成点,即PCG将在整个Landscape地形上生成点,需要注意生成的点越多对机器的性能消耗越大;

  • Setttings/Seed:PCGGraph生成点采用的随机数,更改Seed能动态的更改点的布局;

  • Settings/Points/Apply Density to Points:PCG生成的点是否随机生成密度值,如果取消勾选所有生成的点的密度值将全部被设置成1;

  • Settings/Points/Point Steepness:点的陡度值,影响点的密度值的随机生成,至于时如何影响的暂时未知;

Spline Sampler(样条线采样器)

样条线采样器,接收样条线数据,输出采样结果,目前主要接入的节点就是Get Spline Data、Create Spline两个。

属性

Spline Sampler节点根据使用不同的采样方式和采样模式,可用的参数也不一样。

  • Settings/Dimension:采样器在样条线上的采样方式,采样方式有多个,分别是On Spline(样条线上)、On Horizontal(水平上)、On Vertical(垂直上)、On Volume(体积上)、On Interior(内部上),故名思意On Spline就是在样条线上采样,On Interior就是在样条线内部采样,但是要求样条线必须是封闭的才能进行内部采样,否则采样器会报错,On Volume个人理解是指在样条线在Y轴和Z轴所在的平面上的投影进行采样,On Horizontal就是在样条线在Y轴上的投影采样,On Vertical就是在样条线在Z轴上的投影采样;

  • Settings/Mode:采样器在样条线上的采样模式,有Subdivison(细分)、Distance(距离)、Number Of Samples(样本数量)三种,个人理解Subdivision是在样条线的点与点之间进行细分取点,如果使用Subdivision模式,参数Subdivisions Per Segment(每段细分次数)会变得可用,当参数设置成0时,采样器只会取样条线的点:

    当参数设置成2时,采样器除了取样条线的点外,还会在两点之间的线段分割成两段的分割点上取两个点:

    如果使用Distance模式,参数Distance Increment(距离增量)变得可用,采样器会以某一点为基准,在样条上每隔参数指定距离取一个点:

    如果使用Number Of Samples模式,采样器将在样条线的默认的采样点上取点,此时参数Num Samples(数字采样)变得可用,可以指定采样的密度:

  • Settings/Fill:填充,只在采样方式是On Horizontal(水平上)、On Vertical(垂直上)、On Volume(体积上)时可用,有Fill(填充)和Edges Only(仅边)两个选项,目前没有探索出具体有什么作用;

  • Settings/Subdivisions Per Segment:在采样模式为Subdivison时可用,控制细分段数;

  • Settings/Distance Increment:在采样模式为Distance时可用,控制取点距离;

  • Settings/Num Samples:在采样模式为Number Of Samples时可用,控制取样密度;

  • Settings/Num Planar Subdivisions:数字平面细分,在采样方式为On Horizontal(水平上)、On Volume(体积上)时可用,也没试出具体作用,目前只知道会影响点的密度,值越大密度越小;

  • Settings/Num Height Subdivisions:数字高度细分,在采样方式为On Vertical(垂直上)、On Volume(体积上)时可用,也没试出具体作用,目前只知道会影响点的密度,值越大密度越小;

  • Settings/Compute Tangents

  • Settings/Unbounded:已解除绑定,控制样条线采样器是否接受PCG体积的约束,默认为False接受约束,那么在PCG体积之外的样条线上的采样点将不会被取点:

    如果为Ture则无视PCG体积,在整个样条线上取点:

  • Settings/Interior Sample Spacing:内部采样距离,在采样方式为On Interior(内部上)时可用,控制采样器在样条线内部的采样密度,距离越小采样密度越高;

  • Settings/Interior Border Sample Spacing:内边框采样间距,在采样方式为On Interior(内部上)时可用,控制采样器在样条线上的采样密度,数值越小采样密度越高

  • Settings/Treat Spline as Polyline:将样条线视为折线,在采样方式为On Interior(内部上)时可用,顾名思义,我们拉出来的样条线默认是曲线,在不需要更改样条线的前提下勾选这个参数可以将样条线视为折线,然后采样器将在折线所围的范围内采样;

  • Settings/Interior Orientation:内朝向,在采样方式为On Interior(内部上)时可用,控制采样器的采样点的朝向,有统一和按照曲率两个选项;

  • Settings/Project Onto Surface:投射到表面,在采样方式为On Interior(内部上)时可用,控制采样点是否投射到样条线所在的平面,为Ture时采样点都附着在样条线表面上:

    为False时采样点都附着在样条线最低的那个点所在的XY轴平面上的投影上:

  • Settings/Interior Density Falloff Curve:内部密度衰减曲线,在采样方式为On Interior(内部上)时可用,曲线的X轴表示点到边界距离,数值取0-1,0表示在样条线内部的中心,1表示在样条线上,Y轴为密度值,通过点离中心的距离控制点的密度值,如这样的曲线:

    点的密度分布就是:

  • Settings/Points/Point Steepness:设置点的陡度;

  • Settings/Seeding/Seed from Local Position和Seed from 2D Position:设置随机种子的长生方式;

  • Settings/Next Direction Data Attribute、Curvature Attribute、Segment Index Attribute、Subsegment Index Attribute、Compute Tangents、Arrive Tangent Attribute、Leave Tangent Attribute、Alpha Attribute、Distance Attribute、Input Key Attribute:样条线采样器获取的点除了常规的属性外还多是了很多额外的属性,默认情况这些属性都不显示,需要单独显示是可以勾选这些属性,属性对应的字符串名称就是属性在属性视图中列的名称,名称可以自定义。

小技巧

  • Spline内部的点落在Landscape上:我们在使用样条线采样器的时候可能会碰到这样的情况:

    样条线内部生成的点处于样条线所在的平面而不是落在地表上,即使勾选了Project Onto Surface选项,生成点也是落在样条线最低点所在的XY明面上而非地表,想要点落在地表上有两个解决办法:

    使用Bounds Modifier配合Surface Sampler

    Bounds Modifier修改点的边界,使点的边界尽量与地表相交:

    然后将样条线内的点作为约束形状传入到表面采样器中,这样生成点就是落在样条线的点的边界与地表相交的地方:

    这个方法的缺点是由于经过了两次采样,最终由表面采样器输出的点的数量会比样条线采样器少很多。

    使用PCG蓝图元素ProjectPointsOnLandscape:在/All/EngineData/Plugins/PCG/BP_Elements/Deprecated下UE官方预制了大量的元素模板供我们使用,其中有一个ProjectPointsOnLandscape就是专门用于将点落在Landscape上的元素模板,我们只需要在Execute Blueprint节点的Template/Blueprint Element Type指定元素模板为ProjectPointsOnLandscape即可:

    生成效果是和第一种方法一样的,只是ProjectPointsOnLandscape不会随机点的密度,但生成的点数量保持不变:

Mesh Sampler(网格体采样器)

网格体采样器是Procedural Content Generation Framework (PCG) Geometry Script Interop扩展插件额外提供的采样器,我们想要使用的话需要先启用这个扩展插件。

网格体采样器可以从指定的静态网格体中提取点并输出,注意生成的点默认在世界的坐标远点处,一般我们想要使用这些点需要配合复制点节点将点拷贝走。

属性

  • Settings/Sampling Method:采样方法;
  • Settings/Static Mesh:需要采样静态网格体,目前支持静态网格体,不支持骨骼网格体;
  • Settings/Seed:生成点的随机种子;
  • Color & Density/Color Channel as Density:把模型的颜色通道值设置为点的密度值;
  • Voxelize Options/Voxelize:体素化,采用模型体素化的方式来生成点,体素化生成的点云能更接近模型本身。这里体素化只是对模型的表面进行体素化,并不包含模型内部的体素化。体素化指的是将物体的几何表示形式转换成最接近该物体的体素表示形式,产生体数据集,其不仅包含模型的表面信息,而且能描述模型的内部属性,三维空间的体素可以理解为二位空间的像素,只是在三维空间中将二维空间的像素使用了立方体单元来表示;
  • Voxelize Options/Voxel Size:体素大小,体素越小生成的点越多,点云越接近模型;
  • Voxelize Options/Remove Hidden Triangles:移除隐藏的三角形
  • LODSettings/Requested LODType:请求的LOD类型,不同的LOD等级模型具有的三角面的数量不用,进而生成点的数量也不同;
  • LODSettings/Requested LODIndex:请求的LOD的索引,即LOD级别;
  • Poisson sampling:目前选项都是灰色不可设置状态,暂不知用处;
  • UVs/Extract UV as Attribute:在点的属性列表中增加UV属性列;
  • Extra/Output Triangle Ids:在点的属性列表中增加三角形ID属性列
  • Points/Point Steepness:设置生成的点的陡度;

Copy Points(复制点)

复制点,接收一个Source点集和一个Target点集,将Suorce点集复制到Target点集所在位置,注意Target点集中没有一个点就会复制一份Source点集到点所在的位置,所以这个节点两个输入引脚输入的点都比较多的时候会非常吃性能。

复制点节点的属性Rotation Inheritce(旋转继承)、Scale Inheritce(缩放继承)、Color Inheritce(颜色继承)、Seed Inheritce(种子继承)、Attribute Inheritce(属性继承)、Tag Inheritce(标签继承)等属性都是用于设置复制后的点的属性应该优先继承两个输入中的哪一个。

Select Points(选择点)

选择点这个节点在5.2叫点采样器,主要作用就是对输入的点集进行随机的筛选,输出保留的点集。

属性

  • Settings/Ratio:比率,要保留的输出点的数量占输入输入点的总数的比率;
  • Settings/Seed:随机筛选点的随机种子。

14.Spatical(空间)

Normal To Density(法线转密度)

接收点数据,使用点的法线向量与设置的法线向量执行指定的运算,使用运算结果给点设置新的密度值。

属性

  • Settings/Normal:设置被运算的法线向量;
  • Settings/Offset:设置结果偏移,计算出来的新密度值会加上这个偏移量得出的结果再设到点的密度属性;
  • Settings/Strength:计算强度,Result = Result(1/Strength)
  • Settings/Density Mode:计算模式,要执行的运算方式。

Difference(差异)

输入两个点集Source和Differences,输出Source和Differences差分运算的结果。

属性

  • Settings/Density Function:密度函数,用于在操作后重新计算密度的密度函数;
  • Settings/Mode:模式,描述差分运算如何处理输出数据:连续-非破坏性数据输出将被保持。
    离散-输出数据将是离散点,或显式转换为点。推断-根据源和运算,输出数据将从连续或离散中选择。
  • Settings/Diff Metadata:对比元数据,目前没探索出有什么用;
  • Keep Zero Density Points:输出的点集中是否保留密度为0的点,节点运算结束后,重叠的点的密度会被设置成0,处于边界的点密度都会被设置成0-1之间。

Intersection(相交)

接收多个空间数据,输出所有空间数据相交部分的空间数据,如果不存在都相交的部分则输出空数据。

如:

所有空间数据存在共同相交部分,则:

如果不存在共同的相交部分,则:

Distance(距离)

接收源点集合目标点集,计算源点集中的点到目标点集中心的距离,并为点附加一个Distance(距离)属性,在距离节点之后输出的点就都会附带一个距离属性,可以在点的属性列表中看到。

属性

  • Settings/Output to Attribute:输出到属性,控制是否为输出点集添加距离属性,默认为True,如果取消勾选,则不会添加距离属性到输出点集,之后使用这个点集的节点都无法获取到距离属性;
  • Settings/Output Attribute:输出属性,当Output to Attribute为Ture时可用,将计算结果运用到点的指定属性上,默认是距离,也可以修改成其他的属性,只要目标属性与计算结果的值的类型相同就都可以设置;
  • Settings/Output Distance Vector:输出距离向量,当Output to Attribute为Ture时可用,默认Output to Attribute输出到点的属性列表中的表示只有Distance一列,显示点到中心的距离,勾选后Output to Attribute输出到点的属性列表中的表示将变为XYZ三个坐标用以表示向量;
  • Settings/Set Density:设置密度,更具点到中心的距离设置点的密度,密度值在0-1之间,这里的设置密度和直接在Output Attribute中设的密度不同,这里设置的密度都是被限制在0-1之间的,而如果直接在Output Attribute中设的密度,PCG框架会直接将距离的计算结果设置到点的密度属性上,导致点密度非常大,如果直接在Output Attribute中设密度,那么优先使用Output Attribute的设置,忽略Set Density的设置;
  • Settings/Maximum Distance:从中心向外搜索的距离,一般配合Set Density使用,被搜索到的点会被应用节点的设置,距离之外的点不做设置;
  • Settings/Source Shape:源点集的被视为的边界形状,用于确定中心;
  • Settings/Target Shape:目标点集的被视为的边界形状,用于确定中心。

Create Points(创建点)

根据设置创建点集并输出。

属性

  • Settings/Points to Create:需要创建的点列表,每一个点都可以单独设置坐标、旋转、缩放、密度、最小边界、最大边界、颜色、陡度、种子等;
  • Settings/Coordinate Space:生成点集是要采用的空间坐标类型;
  • Settings/Cull Points Outside Volume:是否剔除在PCG体积之外的点。

Create Points Grid(创建点网格)

在世界坐标的原点处创建一个点的整列并输出,和网格体采样器一样,创建点也位于世界坐标的原点,需要配合复制点节点将点集拷贝到自己需要的地方使用。

属性

  • Settings/Grid Extens:网格范围,控制点矩阵的长宽高;
  • Settings/Cell Size:单元大小,设置点边界大小,根据点的大小不同网格中生成点的数量也不同,但点始终会将网格所表示的体积填满,如果想要更好的看到点的表示可以设置Debug/Scale Methos(缩放方法)为Absolute(绝对),设置Point Scale(点缩放)小一些即可;
  • Settings/Coordinate Space:设置生成点要采用的坐标空间类型;
  • Settings/Set Points Bounds:设定点边界,如为true,点的边界设为50.0,如为false,设为1.0;
  • Settings/Cull Points Outside Volume:是否剔除在PCG体积之外的点;
  • Settings/Point Postion:设置点处于单元格的哪个位置。

Get Spline Data(获取样条线数据)

获取样条线数据,可以采集到世界中的样条线数据输出到PCGGraph图表,样条线可以是在其他的Actor身上也可以是在PCGGraph自身身上。

  • Actor Selector Settings/Actor Filter:筛选包含Spline组件的Actor的方式,有五个筛选方式:Self(自身)、Parent(父项)、Root(根)、All World Actors(所有世界Actor)、Original(初始),一般使用All World Actor,PCG系统会在整个Level中寻找所有带有Spline组件的Actor;
  • Actor Selector Settings/Must Overlap Self:必须重叠自身,即只筛选样条线与PCG体积重叠的Actor,只在Actor Filter选择All World Actors时生效;
  • Actor Selector Settings/Actor Selection:筛选Actor的方式,可以是By Class(按类型筛选)或者By Tag(按标签筛选),只在Actor Filter选择All World Actors时生效;
  • Actor Selector Settings/Actor Selection Class或Tag:选择筛选Actor的类型或者标签,只在Actor Filter选择All World Actors时生效,注意使用按标记搜索时搜索的是Actor的标签并非是Actor下Spline组件的标签;
  • Actor Selector Settings/Select Multiple:是否选择多个Actor,勾选则PCG系统在所有符合要求的样条线上生成点,生成的点数据每个Actor分成一个批输入,不勾选则只在第一个搜索到的样条线上生成点,只在Actor Filter选择All World Actors时生效;
  • Actor Selector Settings/Ignore Self and Children:忽略搜索PCGGraph自身的Spline,在/Actor Filter选择Self、Parent、Root、Original等是则是Include Children,控制是否搜索PCGGraph自身的子Actor组件下的Spline;
  • Data Retrieval Settings/Track Actors Only Within Bounds:只对PCG体积内的Actor进行刷新;

Get Actor Data(获取Actor数据)

可以通过标签或直接获取PCGGraph自身来获取世界中的Actor,将Actor的坐标作为空间数据输入PCGGraph。

Get Landscape Data(获取地形数据)

这个节点是新出的用来取代Input节点中的Landscape引脚的节点,可以直接获取PCG体积所在世界的Landscape数据。

属性

  • Settings/Get Height Only:只获取高度,如果为Ture则节点获取的点在Transform属性上只返回Location,如果为False则节点获取的点返回完整Transform属性;
  • Settings/Get Layer Weights:获取层权重,获取点带有地形层级权重;
  • Settings/Get Actor Reference:获取Actor引用,点的属性附带其引用的Actor路径;
  • Settings/Get Physical Material:获取物理材质,点的属性附带其引用的物理材质路径;
  • Settings/Get Component Coordinates:获取组件坐标,点的属性附带其组件的坐标;

Get Texture Data(获取纹理数据)

通过纹理贴图颜色通道来采样的采样器,采样出来的点集按照通道进行分布;如:

属性

  • Settings/Transform:设置贴图在PCG体积内的变换属性;
  • Settings/Use Absolute Transform:是否使用绝对变换,使用绝对变换之后,贴图的位置和缩放将使用本身的值进行平移和缩放,而不是在填充了体积的基础上进行平移和缩放,由于缩放的默认值为1,所以我们启用了绝对变换时,点就会缩小到我们看不见,需要手动放大很多倍之后才能看得见;
  • Settings/Color Channel:选择要采样的颜色通道;
  • Settings/Filter:用于根据邻近纹素的值确定样本值的方法;
  • Settings/Texel Size:纹素的大小,可以理解为像素或体素,越小生成的点越多,对纹理的还原越高;
  • Settings/Use Advanced Tilling:使用高级平铺,勾选后Tilling选项生效;
  • Settings/Force Editor Only CPU Sampling:强制纯编辑器CPU采样,即使纹理未设为CPU可用,在某些条件下(禁用sRGB、无mipmap和非压缩格式)仍然可以从CPU内存访问它。
    从CPU内存读取比从GPU内存读取更快更准确,因为纹理不会受到压缩或分辨率限制。启用此标记
    以强制复制拥有正确设置的纹理以供CPU内存访问。这为纯编辑器内容。
  • Settings/Texture:要设置的贴图;
  • Settings/Tilling:高级平铺设置;

World Ray Hit Query(世界射线命中查询)

由于很多时候世界中的地形并不是单纯由Landscape构成的,还会包含很多静态网格体,此时单使用表面采样器已经无法精确的对地形表面进行采样了,此时我们就需要配合世界射线命中查询节点来进行表面采样。

世界射线命中查询节点允许对拥有表面似行为的世界中的碰撞进行基于射线投射的泛型访问,使用射线检测来检测碰撞体的表面,输出混合了地形和碰撞体表面的表面数据。如:

属性

  • Data/Set Ray Parameters:设置光线参数,勾选后会出现几个射线的设置项,可以自定设置部分参数;

  • Data/Apply Metadata from Landscape:看FCollisionQueryParams中是否有我们想要公开的一些标记,例如:bReturnFacelndex、bReturnPhysicalMaterial,以及一些忽略模式;

  • Data/Get Reference to Physical Material:在点的属性列表中添加物理材质的引用列;

  • Data/Ignore PCGHits:忽略PCG生成的物体的碰撞,PCG生成的物体也可以是构成地形的一部分,如果勾选了这个选项,那么射线检测时会忽略PCG生成的物体的表面检测,当然静态网格体生成器生成的物体的碰撞类型默认是BlockAllDynamic,这个碰撞类型射线是检测不到的,如果我们想要采集PCG生成的物体的碰撞表面,则需要修改碰撞预设为可以被射线检测到预设类型,如BlockAll。

  • Data/Ignore Self Hits:忽略自我命中,PCG体积也可以在自身身上添加组件设置网格体,这个选项就可以控制是否要检测自身的碰撞表面;

  • Data/Get Reference to Actor Hit:在点的属性列表中增加Actor的引用列;

  • Data/Advanced/Collision Channel:选择射线要检测的碰撞通道,如默认是静态场景,如我们设置成为动态场景,则上面的表面采集就会变成这样:

    因为静态网格体生成器生成的网格体使用的默认碰撞预设就是BlockAllDynamic,所以未修改碰撞预设的小石头就被采样了,而Landscape和大石头就采集不到了;

  • Data/Advanced/Trace Complex:是否启用对网格体复杂碰撞的检测,使用复杂碰撞检测可以是采样点更贴合网格体,但同时也意味着更大的性能消耗;

  • Data/Filtering/Actor Tag Filter:Actor标签过滤器,可以设置只对含有标签列表中的标签的网格体进行检测或排除对包含标签列表中的标签的网格体做检测,默认为无标记过滤,即不启用;

  • Data/Filtering/Actor Tags List:设置Actor标签过滤器使用的标签列表,多个标签用,分割,注意是英文逗号;

  • Data/Filtering/Ignore Landscape Hits:忽略地形命中,单独排除Landscape的检测。

Get Actor Data(获取Actor数据)

GetActorData节点是GetSplineData、GetLandscapeData、GetTextureData等父类,用于获取世界中Actor身上的空间数据。

属性

  • Settings/Actor Filter:筛选节点应该从Actor的那些部位获取数据;

  • Settings/Include Children:是否包含子Actor的数据;

  • Settings/Mode:数据获取的模式,有Parse Actor Components(解析Actor组件),Get Single Point(获取单点),Get Data from Property(从属性获取数据),Get Data from PCGComponent(从PCG分量获取数据),Get Data from PCGComponent or Parse Components(从PCG分量或解析分量获取数据)。

    使用Parse Actor Components模式PCG图表会自行解析Actor属下的组件,凡是带空间数据的组件都可以被读取,比如:Collision、Mesh、Spline等。

    Get Single Point模式主要读取Actor的世界坐标,并将世界坐标作为一个点数据传入图表,常用于CopyPoints节点的Target引脚,如:

    Get Data from Property(从属性获取数据),有点类似Get Actor Property节点,也是通过名字从Actor中获取属性,只是这个节点获取的是空间数据;

    Get Data from PCGComponent(从PCG分量获取数据),这个模式可以从另一个PCG图表的Out输出节点获取空间数据;

    Get Data from PCGComponent or Parse Compoents(从PCG分量或解析分量获取数据),从另一个PCG图表的Out节点获取空间数据,如果图表没有从Out节点输出数据,则自动解析PCG空间数据以获取数据。

Merge(合并)

用于将多分空间数据合并成一份空间数据,可以合并多个分支中的不同数据,也可以合并同一分支中不同批次的数据。

不同分支的数据如:

可以看到不同分支的点集分别是31、42、34、38,与合并之后的145个点正好相等。

不同批次的数据则是:

因为GetSplineData在勾选选择多个样条线的时候,获取的数据是按Actor分批输入的,比如上图中的0与1两批数据点,对于支持分批数据的节点如TransformPoints等使用起来是正常的,对于不支持分批数据的节点如ProjectPointsonLandscape,则只会对0号索引批次的数据生效,此时则需要使用Merge节点将多个批次的数据合并成一个批次。

Projection(投影)

功能更强大的ProjectPointsOnLandscape节点,可以将数据投影到任何由Projection Target引脚输入的数据集上,并且可以自定义要投影的属性。

15.Spawner(生成器)

Static Mesh Spawner(静态网格体生成器)

静态网格体生成器,专门用于程序化生成静态网格体,生成的静态网格体会按层优化为层级实例化静态网格体组件(Hierarchical Instanced Static Mesh Component)。

属性

  • Settings/Mesh Selector Type:网格体选择器类型,即生成网格体的模式,目前有三种模式:PCGMeshSelectorByAttribute,通过点集中的值为网格体资产引用路径的属性来生成、PCGMeshSelectorWeighted,直接在静态网格体生成器节点的Settings/Mesh Entries(网格体条目)中指定要生成的资产,通过设定权重来控制不同资产生成的比重的方式、PCGMeshSelectorWeightedByCategory,引入了分类属性的直接指定资产的生成方式,可以使用点集中的字符串类型的属性值指定节点生成对应名称分类的资产生成。

    PCGMeshSelectorByAttribute模式的使用

    这个网格体选择器类型主要用于将PCG图表要生成的网格体暴露给蓝图,以便可以在蓝图中动态的修改要生成的网格体。

    使用方式就是通过GetActorProperty节点获取蓝图中的StaticMesh类型的变量,然后使用AddAttribute节点将变量的内容添加进点集的属性中,然后就可以通过静态网格体生成器节点的Settings/AttributeName中指定属性名称以获取到输入网格体的资产引用路径,需要注意指定的属性名称应该与AddAttribute设置的输出名称一致。

    Attribute Name是PCGMeshSelectorByAttribute模式特有的设置,用于指定要获取的属性的名称

    Template Descriptor也是PCGMeshSelectorByAttribute模式特有的设置,用于设置传入的网格体的网格体属性,如碰撞、移动性、剔除、光照等。其中Template Descriptor/Component Class属性设置的是PCG优化网格体时要使用那种组件来做载体。

    PCGMeshSelectorWeighted模式的使用:

    PCGMeshSelectorWeighted模式的使用方法就比较简单了,直接在PCGMeshSelectorWeighted模式特有的Mesh Entries属性中设置网格体资产即可。

    PCGMeshSelectorWeightedByCategory模式的使用:

    PCGMeshSelectorWeightedByCategory模式其实就是加入了分类属性的PCGMeshSelectorWeighted模式,和PCGMeshSelectorByAttribute模式一样,需要使用AddAttribute添加一个字符串类型的属性到点集的属性集中,然后就可以在模式特有的Category Attribute设置中指定属性名以获取属性的值,这样节点就可以根据不同的属性值来生成对应预制资产。这里有一个坑,在UE5.3中,在使用这个生成模式时,AddAttribute不可以使用Category作为属性的名称,否则节点不会接收点数据,很坑。

    然后就可以在模式特有的Entries设置中添加分类,并在分类下设置资产。

  • Instance Data Packer Type:设置的数据打包器,应该是和打包时PCG网格体的数据存储有关,具体用法暂还没尝试出来;

  • Instance Data Packer Parameters:和Instance Data Packer Type配套的参数;

  • Out Attribute Name:用于节点接收属性时,向后输出的此属性的名称,如:前面提到的接收网格体引用路径,如果不设置Out Attribute Name或者设置的输出名称和接收的属性名称不同,在输出的点集属性集中就会出现两列值相同的属性。

  • Apply Mesh Bounds to Points:将网格体边界运用于点,如果勾选则点的边界会跟随网体的边界变化,如果不勾选,则点的边界始终保持自身的大小;

  • Seed:静态网格体的随机种子,暂时没试出有什么效果;

  • By Attribute Material Overrides:默认是不启用,作用和debug中的材质覆盖类似,用法暂时不清楚。

16.Subgraph(子图)

Subgraph(子图表)

一个PCGGraph图标执行节点,可以指定PCGGraph资产并封装进节点,以供在其他的PCG图标中使用。可以理解为PCG的函数,可以在Input节点中设置需要传入的参数,在Output节点中设置要返回的结果。

Graph Settings(图设置)

  • Asset Info/Expose to Library:图是否公开到库,如果勾选则右键搜索或在控制面版中搜索都可以搜索到图;
  • Asset Info/Category:图公开到库后的分栏;
  • Asset Info/Description:鼠标悬停在控制面版中图名称时的提示;
  • Settings/Landscape Uses Metadata:配合获取地形数据时使用的设置
  • Settings/Use Hierarchical Generation:配合获取地形数据时使用的设置
  • Graph:图中引用的所有节点;
  • Instance:设置图的全局参数,类似材质参数,可以在实例中修改。

Loop(循环子图)

接收一个分批数据,按批次输入数据到子图中执行,这个是PCG高级用法的基础。

属性

  • Instance/Graph:指定要做循环的子图;
  • Instance/Parameters Overrides:参数设置,如果子图创建了实例参数,则在这个栏目下会显示所有的参数,可以在循环前进行自定义设置;
  • Data/Loop Pins:设置要循环的引脚,由于子图可以自定义添加多个输入引脚,所以可以使用引脚名称指定哪些引脚接收批数据执行循环,如果要指定多个则使用英文的逗号将引脚名称隔开,如果不指定,则默认使用第一个接入数据的引脚作为循环引脚,注意是第一个接入数据的引脚,而不是第一个引脚。

17.未分类

Add Attribute(添加属性)

接收一个点集,向点集的属性列表中添加一个指定的额外的属性。可以直接在节点中添加属性也可以通过Attribute引脚添加外部属性。

属性

  • Settings/Output Target:要输出倒点集属性列表中的属性名称;
  • Settings/Input Source:点集的输入源,一般不用更改;
  • Settings/Type:属性的类型;
  • Settings/xxx Value:属性的值。

三、PCG世界分区

在了解PCG的世界分区应用之前,我们得先了解一下UE5新出的世界分区系统。

1.UE5的世界分区

UE5引入了World Partition这个新的世界分区系统,世界分区的启用没有专门的启动选项,而是在地图创建时就直接启用了,在UE5的新建地图视图中,Open World和Empty Open World两个地图默认启用世界分区,Basic和Empty Level默认不启用世界分区,新的World Partition和传统的Levels是互相冲突的,所以在启用了World Partition的地图中Levels是被禁用的,而在没有启用World Partition的地图Levels可以使用而World Partition被禁用。对于已经创建好的普通地图要启用世界分区,可以使用Tools/Convert Level工具进行快捷转换,或者在控制台使用UnrealEditor.exe QAGame -run=WorldPartitionConvertCommandlet MapName.umap -AllowCommandletRendering指令进行转换,UE5会根据当前地图新建一个支持世界分区的新地图。对于启用了世界分区的地图在World Settings中会多出一个WorldPartitionSetup设置栏,Enable Streaming会被默认启用,即默认启用网格流送。

在世界分区中的Actor会被注册一个WorldPartition设置栏,有两个设置项:

  • WorldPartition/Advanced/Runtime Grid:指定这个Actor所属的网格,默认为None表示使用系统默认分配;
  • WorldPartition/Advanced/Is Spatially Loaded:控制Actor是否跟随流送加载,如果为false,那么Actor只要不在被禁用的数据层中就会始终被加载。

2.场景空间划分

这里我们不过深的去探究UE5对场景划分的技术细节,我们只需要知道UE5是怎么做的就好了,能够服务于我们更好的了解世界分区系统就行了。

UE5将关卡按照配置分割成一个个方格,然后将场景中的Actor划分到一个个方格中,存储到特定的Hash容器中,这个存储容器的类型我们也可以在World Partition Setup/Runtime Hash Class中指定。场景被这样划分了以后就可以使用流送策略只加载需要的场景物体。

在World Settings/World Partition Setup/Runtime Settings可以对场景划分的策略进行有限的配置,在Runtime Partition中系统默认提供了一个2D运行时哈希网格,系统支持使用多个网格,不过按照官方文档建议只使用一个,使用多个会对性能造成影响,如何使用多个哈希网格目前我并没有找到任何资料,大部分情况下也不需要使用多个网格。

  • Runtime Partitions/Index[n]/Class:设置用于存储空间划分单元格的2D运行时哈希网格类型;

  • Runtime Partitions/Index[n]/Name:网格的名称;

  • Runtime Partitions/Index[n]/Main Layer/Cell Size:空间划分单元格的大小,最大无限制,最小为1600;

  • Runtime Partitions/Index[n]/Main Layer/Show Grid Preview:是否显示调试网格,勾选后,在编辑状态下能显示网格,和加载情况;

  • Runtime Partitions/Index[n]/Main Layer/Block on Slow Streaming:在网格单元加载速度不够快时阻塞加载,适用于移动速度很快的情况,在加载来不及时直接不加载了;

  • Runtime Partitions/Index[n]/Main Layer/Client Only Visible:这个配置应该时UE5.4新出的,官方文档还没跟上,自身也没有提示,暂不知用处。

  • Runtime Partitions/Index[n]/Main Layer/Priority:设置流送源的优先级,如果一个网格单元与多个流送源相交,其优先级将是所有流送源中的最高优先级,官方文档是这么描述的,但是我始终没理解;

  • Runtime Partitions/Index[n]/Main Layer/Loading Range:流送源的加载半径,适用于所有源,流送源的加载半径在这里统一设置,不在各个源中单独设置;

  • Runtime Partitions/Index[n]/Main Layer/Debug Color:调试网格的颜色;

  • Runtime Partitions/Index[n]/HLODSetups/Index[n]/Name:

  • Runtime Partitions/Index[n]/HLODSetups/Index[n]/HLODLayers:

  • Runtime Partitions/Index[n]/HLODSetups/Index[n]/Is Spatially Loaded:

  • Runtime Partitions/Index[n]/HLODSetups/Index[n]/Partition Layer/Block on Slow Streaming:

  • Runtime Partitions/Index[n]/HLODSetups/Index[n]/Partition Layer/Client Only Visible:

  • Runtime Partitions/Index[n]/HLODSetups/Index[n]/Partition Layer/Priority:

  • Runtime Partitions/Index[n]/HLODSetups/Index[n]/Partition Layer/Loading Range:

  • Runtime Partitions/Index[n]/HLODSetups/Index[n]/Partition Layer/Debug Color:

3.流送

UE5采用流送源的策略来加载世界分区,处于流送源范围内的分区被加载,以外的被卸载,流送策略会在每一帧被执行。UE5提供两种流送源,PlayerController和WorldPartitionStreamingSourceComponent,每一个玩家控制器都自带一个流送源,在Details/WorldPartition栏可以对流送源进行设置。WorldPartitionStreamingSourceComponent是一个可以应用在任何Actor身上的流送源组件,以便在没有控制器的情况下使用流送源。

4.OFPA

由于启用世界分区的关卡不再支持Levels,这就导致分工协作都要在一个地图中编辑,使用UE4的整个场景中所有的Actor数据都存储在一个umap中的存储方式就不再合适了,所以UE5引入了OFPA技术。

OFPA即One File Per Actor一个文件一个Actor,在World Partition中每个Actor都有一个独立文件存储数据,这样编辑粒度就不再是Level而是更细分的Actor,而Level就只存储对Actor的引用,于是我们就可以发现UE5的umap文件体积都非常小,相对应的UE5在Content文件夹下增加了__ExternalObjects____ExternalActors__两个文件夹,分别用来存储场景中Object和Actor的数据。

5.DataLayer

DataLayer是适配UE5世界分区的Layer,Layer技术在UE4中就已经出来了,只是UE4中提到的比较少,网络上关于Layer的资料也很少,由于在启动世界分区的关卡中不能再使用Levels来分割关卡,而很多时候我们还是需要对大世界中不同的区域进行分割,然后手动的控制加载与卸载时机,而不是全部使用默认的流送功能加载卸载,于是UE5提供了DataLayer功能来做分割,用法其实跟子关卡差不多,将Actor分配到指定的数据层中,然后通过加载与卸载数据层来加载与卸载层中的Actor。

数据层实例编辑

在Window/World Partition/Data Layers Outliner可以打开数据层大纲视图,用于管理所有的数据层实例,在视图的右键菜单中可以对数据层实例进行操作,如:Create New Data Layer With Asset:使用数据层资产来创建新的数据层实例,这种方式创建的数据层实例可以在数据层资产中切换运行时和编辑两种类型,编辑类型的数据层实例只作用于编辑时,用于辅助场景编辑,在运行时不可用,运行时类型的数据层实例在运行时和编辑时都可用;Create New Private Data Layer:创建私有数据成实例,这种方式只能创建编辑类型的数据层实例。

选中Actor和数据层实例点击DataLayer视图右上角的加号或者右键菜单的Add Selected Actor(s) to Selected Data Layer(s)可以将选中的Actor添加到选中的数据层实例中,Actor和数据层实例均支持多选,点击叉号或者右键菜单的Remove Selected Actor(s) from Selected Data Layer(s)可以将选中的Actor移出选中的数据层实例。

除此之外还可以在对应Actor的细节面板的Data Layers/Data Layer Assets中添加数据层资产,这样Actor也可以添加进与资产绑定的数据层实例中,删除资产即可将Actor从对应的实例中移除。

为了更方便的分辨哪个Actor属于哪个数据层实例,可以右键世界大纲的分栏勾选Data Layer显示数据层分栏:

一个Actor可以属于多个数据层实例,当一个Actor属于多个数据层实例时,只要Actor所属的数据层实例中存在被激活的数据层实例,Actor即被加载并显示,所以Actor卸载时需要所属的数据层实例都卸载了Actor才会被卸载。

Data Layer Asset

在内容浏览器的右键菜单的World栏中可以创建数据层资产,一个数据层资产唯一绑定一个数据层实例,多个数据层实例不可共享同一个数据资产。通过程序加载卸载数据层实例时并不是直接操作的数据层实例,而是操作数据层实例绑定的数据层资产。

将数据层资产直接拖进数据层视图中也可以直接创建绑定对应资产数据层实例。

蓝图加载与卸载数据层实例

在运行时使用蓝图加载和卸载数据层实例,UE提供DataLayerManager对象来管理,使用GetDataLayerManager节点来获取管理对象,使用SetDataLayerRuntimeState节点来切换数据层实例的状态:

6.PCG的世界分区

到这里我们就基本了解了UE5的世界分区系统,这有助于我们理解PCG在世界分区中的应用。PCG系统默认是作为一整个Actor存在于世界中的,这不利于流式加载,尤其是PCG覆盖的区域比较大的时候,所以PCG也适配了世界分区。

要开启PCG的世界分区需要到PCG组件的细节面板中启动Settings/Is Partitioned,需要注意的是,如果是直接将PCG图表拖入场景中的情况,需要到场景中对应的PCGVolume中启用,如果是组合到蓝图中的PCG,则直接到PCG组件处启用,PCG图表无法直接启用世界分区。

PCG组件启用世界分区以后重新生成一次,组件就会按照图表的配置适配世界分区,PCG框架会在世界中生成一个PCGWorldActor用于管理所有的分区PCGPartitionActor。当我们关闭世界分区时,系统不会自动删除PCGWorldActor,需要我们自己到Tools下的PCG工具中手动删除。

如果需要配置PCG分区的粒度,需要到PCGWorldActor的细节面板中的Generation Settings/Partition Grid Size选项设置。

四、运行时PCG

未完待续…


【UE5】UE5 PCG
http://example.com/2025/12/28/【UE5】UE5 PCG/
作者
Goulandis
发布于
2025年12月28日
许可协议