来源:知乎
作者:风中翠竹
https://zhuanlan.zhihu.com/p/1990473018858808349
前言
没错,又来开新坑了,这个坑是用来拆解UE的PCG的项目源码的,出于UE PCG目前已经在5.7达到了预备生产的级别,后续肯定会成为UE的重要功能模块之一,对比Houdini有不可替代的优势,为了帮助开发人员能够在实际项目中使用PCG,并且可以对PCG插件进行二次开发,故而写下这个系列,本次系列大概是会填完,不会和之前的很多坑一样半途而废了~(因为有个笨蛋天天催我,受不了了!!)
项目架构
项目位于\Engine\Plugins\PCG下。
主要需要研究的是\Engine\Plugins\PCG\Source下面的三个部分,会大概带一下\Engine\Plugins\PCG\Shaders下面的部分。
在Source文件夹下面有三个核心模块:
PCG:核心运行时模块 PCGEditor:编辑器模块 PCGCompute:GPU计算模块(依赖ComputeFramework)
核心的类层次
UPCGSubsystem (世界子系统)
相当于PCG 系统的中央管理器:
组件注册/注销:管理所有 PCG 组件的生命周期 任务调度:通过ScheduleComponent()、ScheduleGraph()、ScheduleGeneric()调度执行 分区管理:管理APCGPartitionActor和本地组件 缓存管理:提供图缓存接口 IPCGGraphCache 运行时生成:FPCGRuntimeGenScheduler 管理运行时生成 八叉树:PCGComponentOctree 用于空间查询
生命周期继承自UTickableWorldSubsystem,每帧调用 Tick()
大部分操作线程安全,使用锁保护
UPCGComponent (PCG组件)
附加到 Actor 的组件,是 PCG 的执行入口:
关键属性:
GraphInstance:持有的图实例(UPCGGraphInstance) GeneratedResources:生成的资源列表(UPCGManagedResource) CurrentGenerationTask:当前生成任务ID GenerationGridSize:生成网格大小
关键方法:
Generate() / GenerateLocal():触发生成 Cleanup() / CleanupLocal():清理生成结果 GetPCGData():获取组件数据(Actor、Landscape等)
执行状态:FPCGComponentExecutionState 实现 IPCGGraphExecutionState
分区支持:bIsComponentPartitioned 控制是否分区,分区时创建本地组件
UPCGGraph (图资产)
PCG 图的定义,包含节点和边。也就是连连看实现啦~
关键属性:
Nodes:节点数组 InputNode / OutputNode:输入/输出节点 UserParameters:用户参数(FInstancedPropertyBag) CookedCompilationData:编译后的数据(用于运行时)
关键方法:
AddNode() / RemoveNode():节点管理 AddEdge() / RemoveEdge():边管理 GetNodeGenerationGridSize():获取节点网格大小
分层生成:bUseHierarchicalGeneration 启用分层生成,HiGenGridSize 定义默认网格
UPCGGraphInstance (图实例)
图的实例化,支持参数覆盖。目的是允许同一图在不同组件中使用不同参数
关键属性:
Graph:指向的图(UPCGGraphInterface) ParametersOverrides:参数覆盖(FPCGOverrideInstancedPropertyBag)
UPCGNode (图节点)
图中的节点,连接 Settings 和 Element
关键属性:
SettingsInterface:设置接口(UPCGSettingsInterface) InputPins / OutputPins:输入/输出引脚数组 NodeTitle:节点标题
关键方法:
UpdatePins():根据设置更新引脚 GetPassThroughInputPin() / GetPassThroughOutputPin():禁用时的透传引脚
引脚管理:引脚通过 UPCGPin 对象管理,支持动态类型
UPCGPin (引脚)
节点的输入/输出连接点,类似于Houdini节点的多个输入和输出~
关键属性:
Properties:引脚属性(FPCGPinProperties) Label:引脚标签 AllowedTypes:允许的数据类型 PinStatus:状态(Normal/Required/Advanced) Usage:用途(Normal/Loop/Feedback) Edges:连接的边数组
关键方法:
AddEdgeTo() / BreakEdgeTo():连接管理 IsCompatible():兼容性检查
UPCGEdge (边)
负责节点间的连接,定义数据流向
关键属性:
InputPin:上游引脚 OutputPin:下游引脚
FPCGGraphExecutor (图执行器)
图(节点)的编译和执行调度
关键组件:
GraphCompiler:图编译器(FPCGGraphCompiler) GraphCache:图缓存(FPCGGraphCache) Tasks:任务映射(TMap<FPCGTaskId, FPCGGraphTask>) TaskOutputs:任务输出(TMap<FPCGTaskId, FOutputDataInfo>)
执行流程:由Schedule()调度图执行,然后Execute()每帧调用执行任务,由ProcessScheduledTasks()处理待执行任务,再有QueueNextTasks()负责队列后续任务。
有如下几个任务状态:
ScheduledTasks:已调度任务 ReadyTasks:就绪任务 ActiveTasks:活跃任务(多线程) ActiveTasksGameThreadOnly:主线程任务 PausedTasks:暂停任务
使用多级锁来保证线程安全~
FPCGGraphCompiler (图编译器)
将图(节点)编译为任务列表
关键方法:
Compile():编译图 GetCompiledTasks():获取编译后的任务 CullTasks():剔除不需要的任务
编译结果存储在 FPCGGraphCompilerCache 中
编译时也有一些优化,但是不重要,这里就不写了~
FPCGGraphTask (图任务)
编译后的单个执行任务
关键属性:
Inputs:输入任务列表(FPCGGraphTaskInput) Element:执行元素(FPCGElementPtr) Node:关联节点 Context:执行上下文 ElementSource:元素来源(Trivial/FromNode/FromCookedSettings等) PinDependency:引脚依赖表达式
任务输入:FPCGGraphTaskInput 包含:
TaskId:上游任务ID UpstreamPin / DownstreamPin:引脚信息 bProvideData:是否提供数据 bIsUsedMultipleTimes:是否被多次使用
FPCGGraphActiveTask (活跃任务)
正在执行的任务
Context:执行上下文(TUniquePtr<FPCGContext>) ExecutingTask:执行任务(UE::Tasks::TTask<bool>) bIsGameThreadOnly:是否仅主线程
生命周期从 ReadyTasks 移动到 ActiveTasks,执行完成后清理。
Element 是 PCG 中节点执行逻辑的实现。架构上采用“配置与执行分离”
Settings定义节点配置、引脚属性、可序列化属性而Element实现节点的执行逻辑
IPCGElement (元素接口)
节点执行逻辑的抽象接口
关键方法:
Initialize():初始化上下文 Execute():执行(可多次调用直到返回true) Abort():中止执行 IsCacheable():是否可缓存 GetDependenciesCrc():获取依赖CRC
在执行阶段:PreExecute()负责执行前准备,PrepareData()准备数据,ExecuteInternal()核心执行(虚函数),PostExecute()执行后处理。
特殊元素:
FPCGFetchInputElement:获取输入元素 FPCGPreGraphElement:图前处理元素 FPCGGenericElement:通用元素(用于lambda) FPCGGridLinkageElement:网格链接元素
UPCGSettings (设置基类)
负责节点配置和引脚定义
关键方法:
CreateElement():创建元素(纯虚函数) InputPinProperties() / OutputPinProperties():定义引脚属性 GetElement():获取元素(带缓存)
关键属性:
Seed:随机种子 bEnabled:是否启用 CachedOverridableParams:可覆盖参数列表
参数覆盖:支持通过图参数覆盖设置属性。
UPCGSettingsInterface (设置接口)
设置的接口抽象,支持节点使用共享设置或实例化设置
实现类:
UPCGSettings:直接设置 UPCGSettingsInstance:设置实例(持有设置引用)
UPCGData (数据基类)
所有PCG数据的基类
关键属性:
UID:唯一ID Crc:CRC校验值 Metadata:元数据(UPCGMetadata)
关键方法:
GetOrComputeCrc():获取或计算CRC DuplicateData():复制数据 VisitDataNetwork():访问数据网络
数据类型则通过 GetDataType() 返回类型枚举
FPCGDataCollection (数据集合)
节点间传递的数据集合
关键属性:
TaggedData:带标签的数据数组(TArray<FPCGTaggedData>) DataCrcs:数据CRC数组 InactiveOutputPinBitmask:非活跃输出引脚位掩码
关键方法:
GetInputsByPin():按引脚获取输入 GetSpatialInputsByPin():按引脚获取空间数据 GetAllSettings():获取所有设置 GetAllParams():获取所有参数
FPCGTaggedData (带标签数据)
单个数据项的包装
关键属性:
Data:数据指针(FPCGDataPtrWrapper) Tags:标签集合 Pin:引脚名称 bIsUsedMultipleTimes:是否被多次使用 OriginalIndex:原始索引(用于缓存)
FPCGContext (执行上下文)
Element执行时的上下文信息
关键属性:
InputData / OutputData:输入/输出数据集合 ExecutionSource:执行源(IPCGGraphExecutionSource) Node:关联节点 TaskId:任务ID CurrentPhase:当前执行阶段 SettingsWithOverride:带覆盖的设置 AsyncState:异步状态
关键方法:
GetInputSettings<T>():获取输入设置(带覆盖) GetSeed():获取种子 ScheduleGraph():调度子图 StoreInCache() / GetFromCache():缓存操作
线程安全:支持多线程创建对象(NewObject_AnyThread())
UPCGManagedResource (管理资源基类)
管理PCG生成的资源
关键方法:
Release():释放资源 ReleaseIfUnused():释放未使用的资源 MoveResourceToNewActor():移动到新Actor
关键属性:
Crc:资源CRC bIsMarkedUnused:是否标记为未使用
UPCGManagedActors (管理Actor)
管理生成的Actor
UPCGManagedComponent (管理组件)
管理单个组件
UPCGManagedISMComponent (管理ISM组件)
管理实例化静态网格组件
UPCGProxyForGPUData (GPU数据代理)
GPU数据的CPU代理,允许CPU节点访问GPU数据,按需回读
关键方法:
GetCPUData():获取CPU数据(触发GPU->CPU回读) GetElementCount():获取元素数量(不触发回读)
节点定义
Elements和Settings是PCG非常重要的概念。
每个节点通常包含两个类:
1.Settings类:UPCG[节点名]Settings
继承自 UPCGSettings 定义节点配置、引脚属性 位置:Public/Elements/[节点名].h
2.Element类:FPCG[节点名]Element
继承自 IPCGElement 实现执行逻辑 位置:同一头文件中(或单独的命名空间)
节点分类和位置
节点的位置都定义在Public/Elements位置下
大致可分为:
1. 基础点操作节点
2. 生成器节点
3. 生成节点(Spawner)
4. 属性/元数据操作节点(Public/Elements/Metadata/)
5. 控制流节点(Public/Elements/ControlFlow/)
6. 输入输出节点(Public/Elements/IO/)
7. 地形相关节点(Public/Elements/Landscape/)
节点定义的标准结构
典型的节点定义文件结构:
// Public/Elements/PCG[节点名].h// 1. 枚举定义(如果需要)UENUM()enumclassEPCG[节点名]Mode:uint8{...};// 2. Settings类定义UCLASS(BlueprintType,ClassGroup=(Procedural))classUPCG[节点名]Settings:publicUPCGSettings{GENERATED_BODY()public:// 节点元信息virtualFNameGetDefaultNodeName()constoverride;virtualFTextGetDefaultNodeTitle()constoverride;virtualEPCGSettingsTypeGetType()constoverride;protected:// 引脚定义virtualTArray<FPCGPinProperties>InputPinProperties()constoverride;virtualTArray<FPCGPinProperties>OutputPinProperties()constoverride;// 创建ElementvirtualFPCGElementPtrCreateElement()constoverride;public:// 可配置属性UPROPERTY(BlueprintReadWrite,EditAnywhere,Category=Settings)// ... 属性定义};// 3. Element类定义classFPCG[节点名]Element:publicIPCGElement{protected:// 核心执行逻辑virtualboolExecuteInternal(FPCGContext*Context)constoverride;// 可选:缓存支持virtualboolIsCacheable(constUPCGSettings*InSettings)constoverride;// 可选:依赖CRCvirtualvoidGetDependenciesCrc(...)constoverride;};节点注册和发现
节点通过以下方式注册到编辑器:
Settings类使用 UCLASS() 宏注册 编辑器扫描 UPCGSettings 的子类 通过反射系统发现所有节点类型 在节点面板中显示
比如,我现在想创建一个属于我自己的节点,应该怎么创建呢?
步骤1:创建头文件
在Source/PCG/Public/Elements/目录下创建头文件,例如PCGMyCustomNode.h:
// Copyright Epic Games, Inc. All Rights Reserved.#pragma once#include"PCGSettings.h"#include"PCGCommon.h"#include"Data/PCGPointData.h" // 根据需要使用#include"PCGMyCustomNode.generated.h"// 1. 定义枚举(如果需要)UENUM()enumclassEPCGMyCustomNodeMode:uint8{ModeA,ModeB,ModeC};// 2. Settings类定义UCLASS(BlueprintType,ClassGroup=(Procedural))classUPCGMyCustomNodeSettings:publicUPCGSettings{GENERATED_BODY()public:UPCGMyCustomNodeSettings();//~Begin UObject interfacevirtualvoidPostLoad()override;#if WITH_EDITORvirtualvoidPostEditChangeProperty(FPropertyChangedEvent&PropertyChangedEvent)override;#endif//~End UObject interface//~Begin UPCGSettings interface#if WITH_EDITOR// 节点元信息virtualFNameGetDefaultNodeName()constoverride{returnFName(TEXT("MyCustomNode"));}virtualFTextGetDefaultNodeTitle()constoverride{returnNSLOCTEXT("PCGMyCustomNode","NodeTitle","My Custom Node");}virtualFTextGetNodeTooltipText()constoverride{returnNSLOCTEXT("PCGMyCustomNode","NodeTooltip","This is my custom PCG node");}virtualEPCGSettingsTypeGetType()constoverride{returnEPCGSettingsType::PointOps;// 或 Generic, Spatial, Filter等}virtualFLinearColorGetNodeTitleColor()constoverride{returnFLinearColor(0.2f,0.8f,0.4f);// 自定义颜色(可选)}#endif// 是否使用随机种子virtualboolUseSeed()constoverride{returntrue;}// 如果需要随机性protected:// 定义输入引脚virtualTArray<FPCGPinProperties>InputPinProperties()constoverride{TArray<FPCGPinProperties>Pins;// 默认输入引脚(点数据)Pins.Emplace(PCGPinConstants::DefaultInputLabel,// 引脚名称EPCGDataType::Point,// 允许的数据类型true,// 允许多个连接true// 允许多个数据);returnPins;}// 定义输出引脚virtualTArray<FPCGPinProperties>OutputPinProperties()constoverride{returnSuper::DefaultPointOutputPinProperties();// 默认点数据输出}// 创建Element的工厂方法(必须实现)virtualFPCGElementPtrCreateElement()constoverride;//~End UPCGSettings interfacepublic:// 可配置的属性UPROPERTY(BlueprintReadWrite,EditAnywhere,Category=Settings,meta=(PCG_Overridable))EPCGMyCustomNodeModeProcessingMode=EPCGMyCustomNodeMode::ModeA;UPROPERTY(BlueprintReadWrite,EditAnywhere,Category=Settings,meta=(PCG_Overridable))floatCustomParameter=1.0f;UPROPERTY(BlueprintReadWrite,EditAnywhere,Category=Settings,meta=(PCG_Overridable))boolbEnableFeature=true;};// 3. Element类定义classFPCGMyCustomNodeElement:publicIPCGElement{public:// 可选:缓存支持virtualboolIsCacheable(constUPCGSettings*InSettings)constoverride{returntrue;// 如果输出是确定性的}// 可选:依赖CRC(用于缓存)virtualvoidGetDependenciesCrc(constFPCGGetDependenciesCrcParams&InParams,FPCGCrc&OutCrc)constoverride;protected:// 核心执行逻辑(必须实现)virtualboolExecuteInternal(FPCGContext*Context)constoverride;// 可选:执行循环模式(用于按数据缓存)virtualEPCGElementExecutionLoopModeExecutionLoopMode(constUPCGSettings*Settings)constoverride{returnEPCGElementExecutionLoopMode::SinglePrimaryPin;// 或 NotALoop}// 可选:支持基础点数据输入virtualboolSupportsBasePointDataInputs(FPCGContext*InContext)constoverride{returntrue;}};步骤2:创建实现文件
在Source/PCG/Private/Elements/目录下创建实现文件,例如PCGMyCustomNode.cpp:
// Copyright Epic Games, Inc. All Rights Reserved.#include"Elements/PCGMyCustomNode.h"#include"PCGContext.h"#include"PCGPin.h"#include"Data/PCGSpatialData.h"#include"Data/PCGBasePointData.h"#include"Helpers/PCGAsync.h"#include"Helpers/PCGHelpers.h"#includeUE_INLINE_GENERATED_CPP_BY_NAME(PCGMyCustomNode)#define LOCTEXT_NAMESPACE "PCGMyCustomNode"// Settings构造函数UPCGMyCustomNodeSettings::UPCGMyCustomNodeSettings(){// 初始化默认值ProcessingMode=EPCGMyCustomNodeMode::ModeA;CustomParameter=1.0f;bEnableFeature=true;}voidUPCGMyCustomNodeSettings::PostLoad(){Super::PostLoad();// 数据迁移逻辑(如果需要)}#if WITH_EDITORvoidUPCGMyCustomNodeSettings::PostEditChangeProperty(FPropertyChangedEvent&PropertyChangedEvent){Super::PostEditChangeProperty(PropertyChangedEvent);// 属性改变时的处理逻辑constFNamePropertyName=PropertyChangedEvent.GetPropertyName();if(PropertyName==GET_MEMBER_NAME_CHECKED(UPCGMyCustomNodeSettings,ProcessingMode)){// 处理模式改变}}#endif// 创建ElementFPCGElementPtrUPCGMyCustomNodeSettings::CreateElement()const{returnMakeShared<FPCGMyCustomNodeElement>();}// Element执行逻辑boolFPCGMyCustomNodeElement::ExecuteInternal(FPCGContext*Context)const{TRACE_CPUPROFILER_EVENT_SCOPE(FPCGMyCustomNodeElement::Execute);check(Context);// 1. 获取SettingsconstUPCGMyCustomNodeSettings*Settings=Context->GetInputSettings<UPCGMyCustomNodeSettings>();check(Settings);// 2. 获取输入数据constTArray<FPCGTaggedData>Inputs=Context->InputData.GetInputsByPin(PCGPinConstants::DefaultInputLabel);// 3. 准备输出TArray<FPCGTaggedData>&Outputs=Context->OutputData.TaggedData;// 4. 处理每个输入数据for(constFPCGTaggedData&Input:Inputs){if(!Input.Data){continue;}// 转换为点数据constUPCGSpatialData*SpatialData=Cast<UPCGSpatialData>(Input.Data);if(!SpatialData){PCGE_LOG(Error,GraphAndLog,LOCTEXT("InvalidInputType","Input must be spatial data"));continue;}constUPCGBasePointData*PointData=SpatialData->ToBasePointData(Context);if(!PointData){PCGE_LOG(Error,GraphAndLog,LOCTEXT("InvalidPointData","Unable to convert to point data"));continue;}// 5. 创建输出数据UPCGBasePointData*OutputPointData=FPCGContext::NewPointData_AnyThread(Context);OutputPointData->InitializeFromData(PointData);constint32NumPoints=PointData->GetNumPoints();OutputPointData->SetNumPoints(NumPoints);// 6. 处理每个点FPCGPointValueRangesOutputRanges(OutputPointData,/*bAllocate=*/false);FPCGPointValueRangesInputRanges(PointData,/*bAllocate=*/false);constintSeed=Context->GetSeed();FRandomStreamRandomStream(Seed);for(int32i=0;i<NumPoints;++i){// 复制输入点OutputRanges.SetFromPoint(i,InputRanges.GetPoint(i));// 根据Settings进行自定义处理FPCGPoint&OutPoint=OutputRanges.GetPoint(i);switch(Settings->ProcessingMode){caseEPCGMyCustomNodeMode::ModeA:// 处理模式AOutPoint.Transform.SetLocation(OutPoint.Transform.GetLocation()+FVector(RandomStream.FRandRange(-1.0f,1.0f))*Settings->CustomParameter);break;caseEPCGMyCustomNodeMode::ModeB:// 处理模式Bif(Settings->bEnableFeature){// 自定义逻辑}break;caseEPCGMyCustomNodeMode::ModeC:// 处理模式Cbreak;}}// 7. 添加到输出FPCGTaggedData&Output=Outputs.Emplace_GetRef(Input);Output.Data=OutputPointData;}returntrue;// 执行完成}// 依赖CRC(用于缓存)voidFPCGMyCustomNodeElement::GetDependenciesCrc(constFPCGGetDependenciesCrcParams&InParams,FPCGCrc&OutCrc)const{// 调用基类方法FPCGCrcCrc;IPCGElement::GetDependenciesCrc(InParams,Crc);// 添加Settings相关的CRCif(constUPCGMyCustomNodeSettings*Settings=Cast<UPCGMyCustomNodeSettings>(InParams.Settings)){// 将Settings的关键属性加入CRCCrc.Combine(FCrc::TypeCrc32(Settings->ProcessingMode));Crc.Combine(FCrc::TypeCrc32(Settings->CustomParameter));Crc.Combine(FCrc::TypeCrc32(Settings->bEnableFeature));}OutCrc=Crc;}#undef LOCTEXT_NAMESPACE步骤3:添加到构建系统
在PCG.Build.cs中添加新文件(通常会自动包含,但需确认):
// 通常不需要手动添加,因为使用了通配符// Public/Elements/*.h// Private/Elements/*.cpp步骤4:本地化字符串(可选)
如果需要本地化,在Content/Localization/中添加字符串表。
步骤5:编译和测试
编译项目 在PCG图编辑器中查找新节点 测试节点功能
PCG支持的数据类型
1. 基础数据类型枚举(EPCGDataType)
根据PCGCommon.h中的定义,PCG支持以下数据类型:
点数据(Point)
EPCGDataType::Point - 点数据,PCG的核心数据类型 表示:UPCGPointData, UPCGBasePointData 用途:存储位置、变换、密度、颜色、种子等属性
曲线/样条数据(PolyLine/Spline)
EPCGDataType::Spline - 样条曲线 EPCGDataType::LandscapeSpline - 地形样条 EPCGDataType::PolyLine - 组合类型(Spline | LandscapeSpline) 表示:UPCGSplineData, UPCGPolyLineData, UPCGLandscapeSplineData 用途:路径、道路、河流等线性特征
表面数据(Surface)
EPCGDataType::Landscape - 地形数据 EPCGDataType::Texture - 纹理数据 EPCGDataType::RenderTarget - 渲染目标 EPCGDataType::VirtualTexture - 虚拟纹理 EPCGDataType::BaseTexture - 基础纹理(Texture | RenderTarget) EPCGDataType::Surface - 组合类型(Landscape | BaseTexture | VirtualTexture) 表示:UPCGLandscapeData, UPCGTextureData, UPCGRenderTargetData, UPCGVirtualTextureData 用途:地形采样、纹理采样、表面投影
体积数据(Volume)
EPCGDataType::Volume - 体积数据 表示:UPCGVolumeData 用途:3D空间区域、碰撞体、密度场
图元数据(Primitive)
EPCGDataType::Primitive - 图元数据 表示:UPCGPrimitiveData 用途:基础几何形状(盒子、球体等)
动态网格(DynamicMesh)
EPCGDataType::DynamicMesh - 动态网格 用途:程序化生成的网格几何
静态网格资源(StaticMeshResource)
EPCGDataType::StaticMeshResource - 静态网格资源 表示:UPCGStaticMeshResourceData 用途:引用静态网格资产
组合数据(Composite)
EPCGDataType::Composite - 布尔运算结果 表示:UPCGUnionData, UPCGIntersectionData, UPCGDifferenceData 用途:并集、交集、差集等布尔运算
空间数据(Spatial)
EPCGDataType::Spatial - 空间数据(Composite | Concrete) 表示:UPCGSpatialData(基类) 用途:所有具有空间位置的数据类型的基类
参数数据(Param/Attribute Set)
EPCGDataType::Param - 属性集合 表示:UPCGUserParametersData 用途:存储元数据属性,不绑定空间位置
其他类型
EPCGDataType::Settings - 设置数据(隐藏) EPCGDataType::Other - 其他类型 EPCGDataType::ProxyForGPU - GPU代理数据(隐藏) EPCGDataType::Any - 任意类型(所有类型的组合)
2. 数据类型层次结构
UPCGData (基类)├── UPCGSpatialData (空间数据基类)│ ├── UPCGBasePointData (点数据基类)│ │ ├── UPCGPointData (点数据)│ │ └── UPCGPointArrayData (点数组数据)│ ├── UPCGPolyLineData (折线数据基类)│ │ ├── UPCGSplineData (样条数据)│ │ └── UPCGLandscapeSplineData (地形样条)│ ├── UPCGSurfaceData (表面数据基类)│ │ ├── UPCGLandscapeData (地形数据)│ │ ├── UPCGTextureData (纹理数据)│ │ ├── UPCGRenderTargetData (渲染目标)│ │ └── UPCGVirtualTextureData (虚拟纹理)│ ├── UPCGVolumeData (体积数据)│ ├── UPCGPrimitiveData (图元数据)│ ├── UPCGUnionData (并集)│ ├── UPCGIntersectionData (交集)│ ├── UPCGDifferenceData (差集)│ └── UPCGProjectionData (投影数据)├── UPCGUserParametersData (参数数据)├── UPCGResourceData (资源数据基类)│ └── UPCGStaticMeshResourceData (静态网格资源)└── UPCGDataPtrWrapper (数据指针包装器)3. 数据类型操作能力
点数据(Point)操作
创建、变换、复制、过滤 属性操作:添加、修改、删除元数据 采样:从其他空间数据类型采样点 生成:网格、球体、表面采样等
空间数据(Spatial)通用操作
采样:SamplePoint() - 在给定位置采样点 投影:ProjectPoint() - 投影点到表面 边界:GetBounds() - 获取边界框 密度查询:GetDensityAtPosition() - 查询位置密度 转换:ToPointData() - 转换为点数据 ToBasePointData() - 转换为基础点数据
表面数据(Surface)操作
地形采样:从Landscape采样高度、法线等 纹理采样:从Texture采样颜色、密度 表面投影:将点投影到表面 UV坐标:计算UV坐标
体积数据(Volume)操作
体素化:将体积转换为体素 密度场:查询3D空间中的密度 边界检测:检测点是否在体积内
样条数据(Spline)操作
沿样条采样:在样条上生成点 距离查询:查询点到样条的距离 切线/法线:获取样条的方向信息
组合数据(Composite)操作
并集(Union):合并多个空间数据 交集(Intersection):计算重叠区域 差集(Difference):从一个数据中减去另一个
实际上,PCG可以具有完整资产生成能力
几何资产
Static Mesh(静态网格) Skinned Mesh(蒙皮网格) Spline Mesh(样条网格) Dynamic Mesh(动态网格)
组件资产
Spline Component(样条组件) Spline Mesh Component(样条网格组件) 任意ActorComponent子类
Actor资产
任意Actor类型 可包含任意组件组合
数据资产
Collision Data(碰撞数据) Spline Data(样条数据) Surface Data(表面数据) Texture Data(纹理数据) RenderTarget(渲染目标)
特殊资产
Grass Maps(草地图) Debug Visualizations(调试可视化)
大体上,我们就过完了PCG这个插件的基本架构,后面的章节会对具体的常用的节点做出详细的解释,以及算法实现的解释。
· 推荐阅读·
入行并扎根游戏大厂的秘诀:在关键节点做对“选择题”

无界游戏学社是由行业资深专家组成的智库型组织。成员均参与过一线知名项目,且平均从业十年以上,掌握了完备的理论知识体系,全面覆盖游戏研发、运营、市场等不同领域。
QQ交流群:892492520
微信联系:gob-kain
夜雨聆风