PCG节点处理的是数据流,也就是点云,点云到底是啥?笼统地说就是一个个携带着信息的点组成的集合。但是在具体是使用过程中,我们还得了解这些”携带着信息的点“是如何被层层包装起来的。本文中老王就和大家一边拆解源代码一边做实验,尝试着深入理解一下PCG中的数据流。如有错误,敬请指正!
文章目录
- 1. FPCGDataCollection
- 2. FPCGTaggedData
- 3. UPCGData
- 3.1 UPCGSpatialData
- 3.1.1 UPCGPointData
- 3.1.2 UPCGSpatialDataWithPointCache
- 4. UPCGMetadata
- 5. FPCGPoint
- 6. 小结

1. FPCGDataCollection
Execute和Execute with Context共同的输入参数,是Input,它的类型是FPCGDataCollection,我们先看一下它源代码中最核心的部分:
USTRUCT(BlueprintType)
struct PCG_API FPCGDataCollection
{
GENERATED_BODY()
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Data)
TArray<FPCGTaggedData> TaggedData;
}
一个TaggedData的数组,每一个TaggedData,对应着这个节点的一个输入连接,我们可以写个简单的代码试验一下:


LogBlueprintUserMessages: [BP_CustomNode_C_20] Tagged Data 数量:3
接下来我们看一下FPCGTaggedData的内容。
2. FPCGTaggedData
我们先看一下FPCGTaggedData源代码中最核心的部分:
USTRUCT(BlueprintType)
struct PCG_API FPCGTaggedData
{
GENERATED_BODY()
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Data)
TObjectPtr<const UPCGData> Data = nullptr;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Data)
TSet<FString> Tags;
};
如上文所述每个FPCGTaggedData对应着一条输入连接,每一条输入连接可能来自一个Actor、一个Spline、一个Landscape以及上一级节点的加工,那么每一条输入就会携带者原始Actor的Tag或者后添加上去的Tag。因此FPCGTaggedData包含最重要的两部分信息就是UPCGData的指针和Tag的集合。
我们再看一下什么是UPCGData
3. UPCGData
UPCGData是PCG中各种类型信息的基类

UCLASS(BlueprintType, ClassGroup = (Procedural))
class PCG_API UPCGData : public UObject
{
GENERATED_BODY()
public:
/** Unique ID for this object instance. */
UPROPERTY(Transient)
uint64 UID = 0;
private:
/** Serves unique ID values to instances of this object. */
static inline std::atomic<uint64> UIDCounter{ 1 };
}
UPCGData最核心的部分就是让每一个UPCGData都有一个全局唯一的UID,也就是说无论你的UPCGData是在何时生成(获取)的,它的UID都是全局唯一的。从上面的类图可以看到,在PCG中,我们经常使用的Data类型,不仅都派生自UPCGData,它们实际也都派生自UPCGSpatialData。
3.1 UPCGSpatialData
空间相关的UPCGData
UCLASS(Abstract, BlueprintType, ClassGroup = (Procedural))
class PCG_API UPCGSpatialData : public UPCGData
{
GENERATED_BODY()
// Not accessible through blueprint to make sure the constness is preserved
UPROPERTY(VisibleAnywhere, Category = Metadata)
TObjectPtr<UPCGMetadata> Metadata = nullptr;
}
相对于UPCGData,每个UPCGSpatialData多了一个UPCGMetadata,UPCGMetadata的作用就是允许用户自定义特性Attributes
UPCGSpatialData类有两个大的派生分支UPCGPointData和UPCGSpatialDataWithPointCache
3.1.1 UPCGPointData
UCLASS(BlueprintType, ClassGroup = (Procedural))
class PCG_API UPCGPointData : public UPCGSpatialData
{
GENERATED_BODY()
UPROPERTY()
TArray<FPCGPoint> Points;
}
UPCGPointData中最重要的就是包含FPCGPoint数组,也就是说一个UPCGPointData对着一组Point。
3.1.2 UPCGSpatialDataWithPointCache
UCLASS(Abstract, ClassGroup = (Procedural))
class PCG_API UPCGSpatialDataWithPointCache : public UPCGSpatialData
{
GENERATED_BODY()
UPROPERTY(Transient)
mutable TArray<TObjectPtr<const UPCGPointData>> CachedBoundedPointData;
}
UPCGSpatialDataWithPointCache包含了一个UPCGPointData数组(间接包含了若干个FPCGPoint数组)
4. UPCGMetadata
注意:
UPCGMetadata并不派生自UPCGData
先看一下核心代码:
UCLASS(BlueprintType)
class PCG_API UPCGMetadata : public UObject
{
GENERATED_BODY()
UPROPERTY()
TObjectPtr<const UPCGMetadata> Parent;
UPROPERTY()
TSet<TWeakObjectPtr<const UPCGMetadata>> OtherParents;
TMap<FName, FPCGMetadataAttributeBase*> Attributes;
}
UPCGMetadata也就是元数据,包含着Attributes的名称和值的Map,以及这些Attributes的来源,加上针对Attributes的各种操作。
在官方的文档中,自定义的特性叫做Attribute,而Point原生的属性叫做Property。Property直接定义在FPCGPoint中。
5. FPCGPoint
USTRUCT(BlueprintType)
struct PCG_API FPCGPoint
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Properties)
FTransform Transform;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Properties)
float Density = 1.0f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Properties)
FVector BoundsMin = -FVector::One();
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Properties)
FVector BoundsMax = FVector::One();
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Properties)
FVector4 Color = FVector4::One();
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Properties, meta = (ClampMin = "0", ClampMax = "1"))
float Steepness = 0.5f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Properties)
int32 Seed = 0;
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Properties|Metadata")
int64 MetadataEntry = -1;
};
在FPCGPoint中除了属性Property的定义,还有一个int64类型的MetadataEntry,这个MetadataEntry应该就对应着Point和Metadata(也就是Attribute)的关联方式。但是具体的算法还需要进一步研究。
/** Adds a unique entry key to the metadata */
UFUNCTION(BlueprintCallable, Category = "PCG|Metadata")
int64 AddEntry(int64 ParentEntryKey = -1);
int64 UPCGMetadata::AddEntry(int64 ParentEntry)
{
FWriteScopeLock ScopeLock(ItemLock);
return ParentKeys.Add(ParentEntry) + ItemKeyOffset;
}
6. 小结
Execute的Input是一个FPCGDataCollection,它包含多个FPCGTaggedData- 每个
FPCGTaggedData对应一个输入源 FPCGTaggedData夹带着一串Tag和一个UPCGData(多数时候实际是其派生类UPCGSpatialData)- 每个
UPCGSpatialData(UPCGPointData或UPCGSpatialDataWithPointCache)对应着一组Point - 每个
Point已包含固有属性(Property)通过int64的MetadataEntry关联到自己的特性(Attribute)



















