在使用了PCGBlueprintElement蓝图编写PCG节点以及C++编写节点后,认为通过C++可以更方便的访问和操作数据,尤其是在PCG这种对属性以及数学运算有一定相关需求的场景。而通过C++也可以拥有更好的性能、选择普通处理或使用PCG中提供的多线程处理等多种方式。
PCG-C++中有两个重要的基类,分别是UPCGSettings和IPCGElement。
- U字开头的UPCGSettings负责在PCGGraph中保存节点的名字、输入输出口信息、节点上的设置等内容,以及创建IPCGElement的功能。
- IPCGElement则负责PCG的计算,可能是单线程的,也可能是多线程的,看具体实现。
编写样例:给一组数据生成一个确定的Seed序列
需求:PCG的多个样例与随机节点中都使用了位置作为Seed其中的一项计算值,这样会导致修改位置后Seed被修改,点云也会重新进行随机计算,没有办法修改已经制作好的外观的位置。
实现:
#pragma once #include "CoreMinimal.h" #include "PCGSettings.h" #include "Elements/PCGPointOperationElementBase.h" #include "UObject/Object.h" #include "PCGDeterministicRandomSettings.generated.h" UCLASS(Blueprintable, BlueprintType) class HYPERPCG_API UPCGDeterministicRandomSettings : public UPCGSettings { GENERATED_BODY() public: UPCGDeterministicRandomSettings(); virtual FPCGElementPtr CreateElement() const override; #if WITH_EDITOR virtual FName GetDefaultNodeName() const override { return "DeterministicRandom"; } virtual EPCGSettingsType GetType() const override { return EPCGSettingsType::Spatial; } #endif virtual TArray<FPCGPinProperties> InputPinProperties() const override; virtual TArray<FPCGPinProperties> OutputPinProperties() const override; }; class FPCGDeterministicRandomElement : public IPCGElement { public: virtual bool ExecuteInternal(FPCGContext* Context) const override; };
GetDefaultNodeName和GetType这几个都要在WITH_EDITOR内,否则这
cpp实现部分
#include "PCGDeterministicRandomSettings.h" #include "PCGContext.h" #include "Data/PCGPointData.h" #include "Helpers/PCGHelpers.h" UPCGDeterministicRandomSettings::UPCGDeterministicRandomSettings() { bUseSeed = true; } FPCGElementPtr UPCGDeterministicRandomSettings::CreateElement() const { return MakeShared<FPCGDeterministicRandomElement>(); } TArray<FPCGPinProperties> UPCGDeterministicRandomSettings::InputPinProperties() const { TArray<FPCGPinProperties> PinProperties; FPCGPinProperties& InputPinProperty = PinProperties.Emplace_GetRef(PCGPinConstants::DefaultInputLabel, EPCGDataType::PointOrParam); InputPinProperty.SetRequiredPin(); return PinProperties; } TArray<FPCGPinProperties> UPCGDeterministicRandomSettings::OutputPinProperties() const { TArray<FPCGPinProperties> PinProperties; PinProperties.Emplace(PCGPinConstants::DefaultOutputLabel, EPCGDataType::PointOrParam); return PinProperties; } bool FPCGDeterministicRandomElement::ExecuteInternal(FPCGContext* Context) const { auto Settings = Context->GetInputSettings<UPCGDeterministicRandomSettings>(); FRandomStream RandomStream = Context->GetSeed(); auto InputData = Context->InputData.GetInputsByPin(PCGPinConstants::DefaultInputLabel); auto& OutputData = Context->OutputData.TaggedData; for (auto& Source : InputData) { auto& Output = OutputData.Emplace_GetRef(Source); Output.Pin = PCGPinConstants::DefaultOutputLabel; auto DataPtr = Cast<UPCGPointData>(Output.Data->DuplicateData()); for (FPCGPoint& MutablePoint : DataPtr->GetMutablePoints()) { MutablePoint.Seed = RandomStream.GetCurrentSeed(); } Output.Data = DataPtr; } return true; }
为了序列的稳定则直接使用循环计算而不是多线程。