虚幻引擎程序化资源生成框架PCG 之Gather(收集)、Merge(合并)、Union(并集)

有朋友询问:Gather(收集)、Merge(合并)、Union(并集)这三个运算节点,看名字有些相似,究竟区别是什么?目前还没有详细的官方文档,所以今天老王结合源代码,尝试分析一下。

文章目录

  • Gather(收集)
    • Gather的作用:
  • Merge(合并)
    • Merge的作用:
  • Union(并集)
    • Union的作用:
  • 小结

Gather(收集)

虚幻引擎程序化资源生成框架PCG 之Gather(收集)、Merge(合并)、Union(并集)_第1张图片

bool FPCGGatherElement::ExecuteInternal(FPCGContext* Context) const
{
	TRACE_CPUPROFILER_EVENT_SCOPE(FPCGGatherElement::Execute);

	Context->OutputData = Context->InputData;

	return true;

}

Gather的作用:

  • FPCGDataCollection:输入端所有FPCGDataCollection合并成一个FPCGDataCollection,对数据不做任何处理,所以最终输出端的FPCGDataCollection数量为1。
  • FPCGTaggedData:最终输出端的FPCGTaggedData数量为输入端所有FPCGDataCollection中包含的FPCGTaggedData数量总和。
  • PCGPoint:最终输出端的PCGPoint数量为输入端所有FPCGDataCollection中包含的PCGPoint数量总和。

小结: Gather就是对FPCGDataCollection简单汇总操作。

Merge(合并)

虚幻引擎程序化资源生成框架PCG 之Gather(收集)、Merge(合并)、Union(并集)_第2张图片

bool FPCGMergeElement::ExecuteInternal(FPCGContext* Context) const
{
	TRACE_CPUPROFILER_EVENT_SCOPE(FPCGMergeElement::Execute);
	check(Context);

	const UPCGMergeSettings* Settings = Context->GetInputSettings<UPCGMergeSettings>();
	check(Settings);

	const bool bMergeMetadata = Settings->bMergeMetadata;

	TArray<FPCGTaggedData> Sources = Context->InputData.GetInputs();
	TArray<FPCGTaggedData>& Outputs = Context->OutputData.TaggedData;

	if (Sources.IsEmpty())
	{
		return true;
	}

	UPCGPointData* TargetPointData = nullptr;
	FPCGTaggedData* TargetTaggedData = nullptr;

	// Prepare data & metadata
	// Done in two passes for futureproofing - expecting changes in the metadata attribute creation vs. usage in points
	for (const FPCGTaggedData& Source : Sources)
	{
		const UPCGPointData* SourcePointData = Cast<const UPCGPointData>(Source.Data);

		if (!SourcePointData)
		{
			PCGE_LOG(Error, GraphAndLog, LOCTEXT("UnsupportedDataType", "Unsupported data type in merge"));
			continue;
		}

		if (!TargetPointData)
		{
			TargetPointData = NewObject<UPCGPointData>();
			TargetPointData->InitializeFromData(SourcePointData, nullptr, bMergeMetadata);

			TargetTaggedData = &(Outputs.Emplace_GetRef(Source));
			TargetTaggedData->Data = TargetPointData;
		}
		else
		{
			if (bMergeMetadata)
			{
				TargetPointData->Metadata->AddAttributes(SourcePointData->Metadata);
			}
			
			check(TargetTaggedData);
			TargetTaggedData->Tags.Append(Source.Tags); // TODO: only unique? if yes, fix union too
		}
	}

	// No valid input types
	if (!TargetPointData)
	{
		return true;
	}

	TArray<FPCGPoint>& TargetPoints = TargetPointData->GetMutablePoints();
	
	for(int32 SourceIndex = 0; SourceIndex < Sources.Num(); ++SourceIndex)
	{
		const UPCGPointData* SourcePointData = Cast<const UPCGPointData>(Sources[SourceIndex].Data);

		if (!SourcePointData)
		{
			continue;
		}

		int32 PointOffset = TargetPoints.Num();
		TargetPoints.Append(SourcePointData->GetPoints());

		if ((!bMergeMetadata || SourceIndex != 0) && !SourcePointData->GetPoints().IsEmpty())
		{
			TArrayView<FPCGPoint> TargetPointsSubset = MakeArrayView(&TargetPoints[PointOffset], SourcePointData->GetPoints().Num());
			for (FPCGPoint& Point : TargetPointsSubset)
			{
				Point.MetadataEntry = PCGInvalidEntryKey;
			}

			if (bMergeMetadata && TargetPointData->Metadata && SourcePointData->Metadata && SourcePointData->Metadata->GetAttributeCount() > 0)
			{
				TargetPointData->Metadata->SetPointAttributes(MakeArrayView(SourcePointData->GetPoints()), SourcePointData->Metadata, TargetPointsSubset);
			}
		}
	}
	
	return true;
}

Merge的作用:

  • FPCGDataCollection:最终输出端的FPCGDataCollection数量为1。
  • FPCGTaggedData:最终输出端的FPCGTaggedData数量也为1。输入端所有Tag的并集和Attribute的并集作为输出端FPCGTaggedDataTagAttribute。如果两条FPCGTaggedData中有同名Attribute且类型不一致以第一个为准。
  • PCGPoint:最终输出端的PCGPoint数量为输入端所有FPCGDataCollection中包含的PCGPoint数量总和。

小结:MergeFPCGTaggedData层级的合并。

Union(并集)

虚幻引擎程序化资源生成框架PCG 之Gather(收集)、Merge(合并)、Union(并集)_第3张图片

bool FPCGUnionElement::ExecuteInternal(FPCGContext* Context) const
{
	TRACE_CPUPROFILER_EVENT_SCOPE(FPCGUnionElement::Execute);

	const UPCGUnionSettings* Settings = Context->GetInputSettings<UPCGUnionSettings>();
	check(Settings);

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

	const EPCGUnionType Type = Settings->Type;
	const EPCGUnionDensityFunction DensityFunction = Settings->DensityFunction;

	TArray<FPCGTaggedData>& Outputs = Context->OutputData.TaggedData;

	const UPCGSpatialData* FirstSpatialData = nullptr;
	UPCGUnionData* UnionData = nullptr;
	int32 UnionTaggedDataIndex = -1;

	for (FPCGTaggedData& Input : Inputs)
	{
		const UPCGSpatialData* SpatialData = Cast<UPCGSpatialData>(Input.Data);

		// Non-spatial data we're not going to touch
		if (!SpatialData)
		{
			Outputs.Add(Input);
			continue;
		}

		if (!FirstSpatialData)
		{
			FirstSpatialData = SpatialData;
			UnionTaggedDataIndex = Outputs.Num();
			Outputs.Add(Input);
			continue;
		}

		FPCGTaggedData& UnionTaggedData = Outputs[UnionTaggedDataIndex];

		// Create union or add to it
		if (!UnionData)
		{
			UnionData = FirstSpatialData->UnionWith(SpatialData);
			UnionData->SetType(Type);
			UnionData->SetDensityFunction(DensityFunction);

			UnionTaggedData.Data = UnionData;
		}
		else
		{
			UnionData->AddData(SpatialData);
			UnionTaggedData.Tags.Append(Input.Tags);
		}
		
		UnionTaggedData.Data = UnionData;
	}

	return true;
}
UnionData = FirstSpatialData->UnionWith(SpatialData);

Union的关键是对FPCGSpatialData进行并集运算。符合条件的FPCGSpatialData会合并成1个。

Union的作用:

  • FPCGDataCollection:最终输出端的FPCGDataCollection数量为1。
  • FPCGTaggedData:最终输出端的FPCGTaggedData数量也为1。
  • PCGPoint:最终输出端的PCGPoint数量输入端所有FPCGDataCollection中包含的PCGPoint数量总和。

小结

简单地说:Gather(收集)、Merge(合并)、Union(并集)依次是从FPCGDataCollection层级、FPCGTaggedData层级、PCGPoint(FPCGSpatialData)层级和“合并”运算。

你可能感兴趣的:(UE5程序化内容生成(PCG),老王的游戏开发教程,虚幻引擎图文笔记,虚幻,java,前端)