PCG – Node anatomy (C++)

By jjeromegerstch

There are not a lot of ressources for now on the topic. Here I’ll give an overview of what makes a PCG node and I will go deeper in posts about each specific part

What compose a node ?

PCGSettings

It have two part, for both edit time features and runtime features. PCGSettings is used to define the exposed part of your node, from the inputs outputs definitions to the settings.

Settings contains Node centric runtime informations:

  • Pins definitions
  • The Element to execute (core functionnality of the node)
  • The seed
  • The cache crc
  • Info about being cached or not
  • Any exposed node parameter that you can see in the Settings part of the Details panel of a node

Settings handles the visual part of the node in the graph for edition:

  • Name
  • Title
  • Pin names
  • Node Category
  • Node Description

PCGElement

This is the interface that you have to implement for the element part of the node. Where the execution logic lies.

It also allows to set a few flags about the execution context:

  • CanExecuteOnlyOnMainThread
  • IsCacheableInstance
  • IsCacheable
  • ShouldVerifyIfOutputsAreUsedMultipleTimes
  • ShouldComputeFullOutputDataCrc
  • IsPassthrough
  • IsCancellable
  • SupportsGPUResidentData
  • SupportsBasePointDataInputs

The execution code is done in the ExecuteInternal

PCGContext

It handles the Input and Output data of your node and keeps track of the execution phase of the node and it’s dependencies

It contains the parameters overrides (when you link a node entry for a specific node setting)

You can create a derived class from PCGContext if you need to handle thigs like Asynchronous loading, temporary storing of data, following substeps,…

There is ONE PCGContext by element, all communication between contexts is done through the Output/Input data and overrides that are in the FPCGDataCollection

Execution flow of a node

Data available as Input

The Context -> PCGDataCollection

You can get all the content of the input data through the InputData PCGDataCollection.

It can contain a few different type of data:

  • Settings -> Always here to handle the node specific settings
  • Spatial data -> Point/Surface/Spline/… data holds metadata and transforms
  • Params -> For attribute only input. Like the ones used for Settings overrides or the Input pin if it takes param data

One important thing to know id the Input data is not to be changed. Any change is done on the copy of the data or any new data that we would affect to OutData.

The Context -> PCGSettings

Can be either the source PCGSetting content : Data set at edit time that is node specific

Or the data set at runtime from the graph execution of previous nodes and that overrides the content of PCGSettings

//Get input settings of the PCGAddTag Node as example
const UPCGAddTagSettings* Settings = Context->GetInputSettings<UPCGAddTagSettings>();

The Context -> PCGDataCollection -> PCGParamData

Contains non spatialized data (one value by attribute) data

TArray<FPCGTaggedData> Sources = Context->InputData.GetAllParams();
for (const FPCGTaggedData& Source : Sources)
{
	const UPCGParamData* SourceData = Cast<const UPCGParamData>(Source.Data);
	//Do whatever you want to do whith the ParamData
}

The Context -> PCGDataCollection -> PCGSpatialData

Spatial Data in the form of a metadata where attributes are set and a point array with each point base informations (properties). Attributes can be custom defined and changed along the life of the data through the graph.

const TArray<FPCGTaggedData> Inputs = Context->InputData.GetAllSpatialInputs();

You can get the PointData that are available in your Input. Depending on your needs and node input you can have more than one PointData

const UPCGData* InputData = Inputs[0].Data; 

In a UPCGData that contains points for our example we can iterate on those points to do any process that we need.

const UPCGPointData* InputPointData = Cast<UPCGPointData>(InputData);
//Don't forget the usual null and validity checks
const TArray<FPCGPoint>& Points = InputPointData ->GetPoints();

Thoses FPCGPoint does’nt contains your attributes but only points porperties. If you need thoses they are in the Metadata of your UPCGData !

The Context -> PCGDataCollection -> Metadata

Metadata lives in the UPCGData alongside the other informations like the points if you are using a Spatial data

Any attribute you add to your dataset is store in the Metadata

Attributes are linked to the data of your Points or other data trhough EntryKey You can’t just ask the attribute of point “I” by asking for the attribute of Key “I”, you need to get the Key from your point “I” to get access to the corresponding attribute value.

To carry on Metadata from the inputs of your nodes to the outputs you need to Initialise your output Metadata using the Input Metadata

You can merge the Metadata from different Input to get an output that will give you access to both.

It is possible to manipulate directly the Metadata or to use accessors thought the PCGAttributeAccessorHelpers.

What do you think?

Leave a Reply

Your email address will not be published. Required fields are marked *