在使用了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;
}
为了序列的稳定则直接使用循环计算而不是多线程。