14 KiB
Raw Blame History

title, date, excerpt, tags, rating
title date excerpt tags rating
Untitled 2025-06-03 10:19:25

前言

  1. ShaderWorldPCGInterop
  2. ShaderWorld
  3. ShaderWorldCore

ShaderWorld

ASWorld

AShaderWorldActor

DrawMaterialToRenderTarget

USWorldSubsystem::DrawMaterialToRenderTarget => SWShaderToolBox::DrawMaterial => DrawMaterial_CS_RT

调用路径:

  • AShaderWorldActor::#RetrieveHeightAt(好像没有引用):检索高度
  • AShaderWorldActor::ComputeHeight_Segmented_MapForClipMap
    • AShaderWorldActor::ProcessSegmentedComputation() <- AShaderWorldActor::TerrainAndSpawnablesManagement() <- AShaderWorldActor::Tick()
  • AShaderWorldActor::ComputeHeightMapForClipMap
    • AShaderWorldActor::UpdateClipMap() <- AShaderWorldActor::TerrainAndSpawnablesManagement() <- AShaderWorldActor::Tick()
  • AShaderWorldActor::ComputeDataLayersForClipMap
    • AShaderWorldActor::UpdateClipMap() <- AShaderWorldActor::TerrainAndSpawnablesManagement() <- AShaderWorldActor::Tick()
  • AShaderWorldActor::UpdateCollisionMeshData更新碰撞模型数据。
    • AShaderWorldActor::CollisionGPU() <- AShaderWorldActor::CollisionManagement() <- AShaderWorldActor::Tick()
  • FSpawnableMesh::UpdateSpawnableData
    • AShaderWorldActor::ProcessSegmentedComputation() <- AShaderWorldActor::TerrainAndSpawnablesManagement() <- AShaderWorldActor::Tick()

Cache机制

AShaderWorldActor::ProcessSegmentedComputation() <- AShaderWorldActor::TerrainAndSpawnablesManagement() <- AShaderWorldActor::Tick()

其他Bug

SetTextureParameterValue相关逻辑排查

  • AShaderWorldActor中的SetTextureParameterValue
    • ExportCacheInBounds
    • AssignHeightMapToDynamicMaterial
    • UpdateStaticDataFor
    • ComputeHeight_Segmented_MapForClipMap似乎会设置
    • UpdateCollisionMeshData
    • #InitializeReadBackDependencies
    • InitiateMaterials

UpdateStaticDataFor

ComputeHeight_Segmented_MapForClipMap

  • 作用:
  • 调用顺序AShaderWorldActor::Tick() -> AShaderWorldActor::TerrainAndSpawnablesManagement() -> AShaderWorldActor::ProcessSegmentedComputation() -> ComputeHeight_Segmented_MapForClipMap

// 1) Intersect clipmap with grid quad
// 2) Gather non computed quads
// 3) Allocated Compute element to missing Quad
// 4) Update the indirection data to the new elements
// 5) Update the Clipmap Heightmap with the grid data

UpdateCollisionMeshData

  • 作用:
    1. 判断DynCollisionMat是否有效无效就使用Generator(高度数据生成材质)来创建。
    2. 设置材质参数NoMargin、TexelPerSide、PatchFullSize、MeshScale。
    3. 设置随机种子相关的材质参数。
    4. 设置材质参数PatchLocation。
    5. 生成碰撞数据到CollisionRT
    6. 笔刷功能逻辑ApplyBrushStackToHeightMap()。
    7. ExportPhysicalMaterialID逻辑。
    8. GPU碰撞数据回读ShaderWorld::AsyncReadPixelsFromRT()。
      1. ShaderWorld::GSWReadbackManager.AddPendingReadBack()将回读Task增加TArray<FReadBackTask> PendingReads;
      2. 之后会在USWorldSubsystem::Tick()中调用ShaderWorld::GSWReadbackManager.TickReadBack(),不断检查是否可回读,并进行最终回读。
  • 调用顺序Tick() -> CollisionManagement() -> CollisionGPU() -> UpdateCollisionMeshData()
namespace ShaderWorld
{
	FORCEINLINE void AsyncReadPixelsFromRT(UShaderWorldRT2D* InRT, TSharedPtr<FSWColorRead, ESPMode::ThreadSafe> Destination, TSharedPtr < FThreadSafeBool, ESPMode::ThreadSafe> Completion)
	{

		ENQUEUE_RENDER_COMMAND(ReadGeoClipMapRTCmd)(
			[InRT, HeightData = Destination, Completion = Completion](FRHICommandListImmediate& RHICmdList)
			{
				check(IsInRenderingThread());

				if (HeightData.IsValid() && InRT->GetResource())
				{
					FRDGBuilder GraphBuilder(RHICmdList);
					TSharedPtr<FRHIGPUTextureReadback> ReadBackStaging = MakeShared<FRHIGPUTextureReadback>(TEXT("SWGPUTextureReadback"));
					FRDGTextureRef RDGSourceTexture = RegisterExternalTexture(GraphBuilder, InRT->GetResource()->TextureRHI, TEXT("SWSourceTextureToReadbackTexture"));
					AddEnqueueCopyPass(GraphBuilder, ReadBackStaging.Get(), RDGSourceTexture);
					GraphBuilder.Execute();

					ShaderWorld::GSWReadbackManager.AddPendingReadBack(RHICmdList, GPixelFormats[RDGSourceTexture->Desc.Format].BlockBytes, RDGSourceTexture->Desc.Extent.X, RDGSourceTexture->Desc.Extent.Y, ReadBackStaging, const_cast<TSharedPtr<FSWColorRead, ESPMode::ThreadSafe>&>(HeightData), const_cast<TSharedPtr < FThreadSafeBool, ESPMode::ThreadSafe>&>(Completion));
				}

			});	
	}

InitializeReadBackDependencies

  • 作用初始化几个GPU数据回读用的RT。
  • 调用顺序BeginPlay() -> InitiateWorld() -> InitializeReadBackDependencies()
  1. 初始化3个RTReadRequestLocation、ReadRequestLocationHeightmap、GeneratorDynamicForReadBack。
  2. 会设置TObjectPtr < UMaterialInstanceDynamic> GeneratorDynamicForReadBack各种变量
GeneratorDynamicForReadBack->SetScalarParameterValue("HeightReadBack", 1.f);  
GeneratorDynamicForReadBack->SetTextureParameterValue("SpecificLocationsRT", ReadRequestLocation);  
GeneratorDynamicForReadBack->SetScalarParameterValue("NoMargin", 0.f);  
GeneratorDynamicForReadBack->SetScalarParameterValue("N", N);  
GeneratorDynamicForReadBack->SetScalarParameterValue("NormalMapSelect", 0.f);  
GeneratorDynamicForReadBack->SetScalarParameterValue("HeightMapToggle", 1.f);
  1. 设置随机种子相关Shader Parameter。

InitiateMaterials

作用:初始化TArray<FClipMapMeshElement> Meshes;的Material、Producers 调用顺序BeginPlay() -> InitiateWorld() -> InitiateMaterials()

经过断点调试会设置WorldSettings里的Material地形Material的HeightMap与NormalMap。

SWorldSubsystem->DrawMaterialToRenderTarget

Rebuild逻辑

重要函数

  • AShaderWorldActor::BeginPlay()
  • AShaderWorldActor::Setup()<- TerrainAndSpawnablesManagement(float& DeltaT) <- Tick()

Rebuild逻辑顺序

  1. AShaderWorldActor::BeginPlay() 1.

Debug

  1. AShaderWorldActor::ComputeHeight_Segmented_MapForClipMap 十多次
  2. UpdateCollisionMeshData
  3. AShaderWorldActor::ComputeHeight_Segmented_MapForClipMap 十多次
  4. #RetrieveHeightAt
  5. UpdateCollisionMeshData 3次
  6. AShaderWorldActor::ComputeHeight_Segmented_MapForClipMap 十多次

RetrieveHeightAt

可能存在bug待排查的

  • ShaderWorldSubsystem->LoadSampleLocationsInRT()
  • ShaderWorldSubsystem->DrawMaterialToRenderTarget()

相关变量

  • FThreadSafeBool
    • bProcessingHeightRetrieval
    • bProcessingHeightRetrievalRT
  • MID
    • GeneratorDynamicForReadBack
  • UShaderWorldRT2DUTextureRenderTarget2D
    • ReadRequestLocationRTF_RG32f初始化于InitializeReadBackDependencies() <- InitiateWorld()
    • ReadRequestLocationHeightmapRTF_RGBA8初始化于InitializeReadBackDependencies() <- InitiateWorld()

代码

bool AShaderWorldActor::RetrieveHeightAt(const TArray<FVector>& Origin, const FSWHeightRetrievalDelegate& Callback)
{	
	if (!GeneratorDynamicForReadBack || !SWorldSubsystem)
		return false;

	if (!bProcessingHeightRetrieval.IsValid())
	{
		bProcessingHeightRetrieval = MakeShared<FThreadSafeBool, ESPMode::ThreadSafe>();
		bProcessingHeightRetrieval->AtomicSet(false);
	}
	if (!bProcessingHeightRetrievalRT.IsValid())
	{
		bProcessingHeightRetrievalRT = MakeShared<FThreadSafeBool, ESPMode::ThreadSafe>();
		bProcessingHeightRetrievalRT->AtomicSet(false);
	}


	if (!(*bProcessingHeightRetrieval.Get()) && ReadRequestLocation && ReadRequestLocationHeightmap && GeneratorDynamicForReadBack)
	{
		bProcessingHeightRetrieval->AtomicSet(true);
		bProcessingHeightRetrievalRT->AtomicSet(false);
		HeightRetrieveDelegate = Callback;

		//初始化采样点数组结构体FSWShareableSamplePoints
		PointsPendingReadBacks = MakeShared<FSWShareableSamplePoints, ESPMode::ThreadSafe>();
		TSharedPtr<FSWShareableSamplePoints>& Samples = PointsPendingReadBacks;

		FBox BoundingBoxRead(Origin);

		Samples->PositionsXY.SetNum(25 * 2);
		for (int i = 0; i < 25; i++)
		{
			if (i < Origin.Num())
			{
				Samples->PositionsXY[i * 2] = Origin[i].X;
				Samples->PositionsXY[i * 2 + 1] = Origin[i].Y;
			}
			else
			{
				Samples->PositionsXY[i * 2] = 0.f;
				Samples->PositionsXY[i * 2 + 1] = 0.f;
			}
		}

		if (USWorldSubsystem* ShaderWorldSubsystem = SWorldSubsystem)
		{
			//从渲染线程
			ShaderWorldSubsystem->LoadSampleLocationsInRT(ReadRequestLocation, Samples);

#if SW_COMPUTE_GENERATION
			ShaderWorldSubsystem->DrawMaterialToRenderTarget(
			{   false,
				 false,
				GetWorld()->Scene,
				(float)GetWorld()->TimeSeconds,
				false,
				true,
				ReadRequestLocationHeightmap->SizeX,
				10,
				FVector(0.f),
				true,
				ReadRequestLocation,
				GeneratorDynamicForReadBack,
				ReadRequestLocationHeightmap
			});
#else
			UKismetRenderingLibrary::DrawMaterialToRenderTarget(this, ReadRequestLocationHeightmap, GeneratorDynamicForReadBack);
#endif

			int32 Size_RT_Readback = ReadRequestLocationHeightmap.Get()->SizeX;

			FVector Barycentre = BoundingBoxRead.GetCenter();
			FVector Extent = BoundingBoxRead.GetExtent();
			float gridspacing = Extent.X * 2.0 / (Size_RT_Readback - 1);

			if (IsValid(BrushManager))
				BrushManager->ApplyBrushStackToHeightMap(this, 0, ReadRequestLocationHeightmap.Get(), Barycentre, gridspacing, Size_RT_Readback, true, true, ReadRequestLocation.Get());


			ReadBackHeightData = MakeShared<FSWColorRead, ESPMode::ThreadSafe>();
			ReadBackHeightData->ReadData.SetNum(25);

			ENQUEUE_RENDER_COMMAND(ReadGeoClipMapRTCmd)(
				[InRT = ReadRequestLocationHeightmap, HeightData = ReadBackHeightData, Completion = bProcessingHeightRetrievalRT](FRHICommandListImmediate& RHICmdList)
				{
					check(IsInRenderingThread());

					if (HeightData.IsValid() && InRT->GetResource())
					{
						FRDGBuilder GraphBuilder(RHICmdList);

						TSharedPtr<FRHIGPUTextureReadback> ReadBackStaging = MakeShared<FRHIGPUTextureReadback>(TEXT("SWGPUTextureReadback"));

						FRDGTextureRef RDGSourceTexture = RegisterExternalTexture(GraphBuilder, InRT->GetResource()->TextureRHI, TEXT("SWSourceTextureToReadbackTexture"));

						AddEnqueueCopyPass(GraphBuilder, ReadBackStaging.Get(), RDGSourceTexture);

						GraphBuilder.Execute();

						ShaderWorld::GSWReadbackManager.AddPendingReadBack(RHICmdList, GPixelFormats[RDGSourceTexture->Desc.Format].BlockBytes, RDGSourceTexture->Desc.Extent.X, RDGSourceTexture->Desc.Extent.Y, ReadBackStaging, const_cast<TSharedPtr<FSWColorRead, ESPMode::ThreadSafe>&>(HeightData), const_cast<TSharedPtr < FThreadSafeBool, ESPMode::ThreadSafe>&>(Completion));

					}

				});

			HeightReadBackFence.BeginFence(true);
		}

		return true;
	}

	return false;
}

RequestReadBackLoad

bool USWorldSubsystem::LoadSampleLocationsInRT(UShaderWorldRT2D* LocationsRequestedRT,
                                               TSharedPtr<FSWShareableSamplePoints>& Samples)
{
	if (!RenderThreadResponded)
		return false;

	const SWSampleRequestComputeData ReadBackData(LocationsRequestedRT, Samples);
	SWToolBox->RequestReadBackLoad(ReadBackData);
	return true;
}

SWShaderToolBox

RequestReadBackLoad

void SWShaderToolBox::RequestReadBackLoad(const SWSampleRequestComputeData& Data) const
{
	if (Data.CPU)
		return CPUTools.RequestReadBackLoad(Data);

	ENQUEUE_RENDER_COMMAND(ShaderTools_copy_rt)
		([this, Data](FRHICommandListImmediate& RHICmdList)
			{
				if (Data.SamplesXY && Data.SamplesXY->GetResource())
				RequestReadBackLoad_RT(RHICmdList,Data);
			}
	);

}

void SWShaderToolBox::RequestReadBackLoad_RT(FRHICommandListImmediate& RHICmdList, const SWSampleRequestComputeData& Data) const
{
	if (!(Data.SamplesXY && Data.SamplesXY->GetResource()))
		return;

	FRDGBuilder GraphBuilder(RHICmdList);

		{
			RDG_EVENT_SCOPE(GraphBuilder, "ShaderWorld  PositionReadBack");
			RDG_GPU_STAT_SCOPE(GraphBuilder, ShaderWorldReadBack);

			FIntVector GroupCount;
			GroupCount.X = FMath::DivideAndRoundUp((float)Data.SamplesXY->GetResource()->GetSizeX(), (float)SW_LoadReadBackLocations_GroupSizeX);
			GroupCount.Y = FMath::DivideAndRoundUp((float)Data.SamplesXY->GetResource()->GetSizeY(), (float)SW_LoadReadBackLocations_GroupSizeY);
			GroupCount.Z = 1;

			const FUnorderedAccessViewRHIRef RT_UAV = GraphBuilder.RHICmdList.CreateUnorderedAccessView(Data.SamplesXY->GetResource()->TextureRHI);

			const FRDGBufferRef LocationRequest = CreateUploadBuffer(
				GraphBuilder,
				TEXT("SWLoadSampleLocations"),
				sizeof(float),
				Data.SamplesSource->PositionsXY.Num(),
				Data.SamplesSource->PositionsXY.GetData(),
				Data.SamplesSource->PositionsXY.Num() * Data.SamplesSource->PositionsXY.GetTypeSize()
			);

			const FRDGBufferSRVRef LocationRequestSRV = GraphBuilder.CreateSRV(FRDGBufferSRVDesc(LocationRequest, PF_R32_FLOAT));;

			FLoadReadBackLocations_CS::FPermutationDomain PermutationVector;
			TShaderMapRef<FLoadReadBackLocations_CS> ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel), PermutationVector);
	
			FLoadReadBackLocations_CS::FParameters* PassParameters = GraphBuilder.AllocParameters<FLoadReadBackLocations_CS::FParameters>();
			PassParameters->SampleDim = Data.SamplesXY->GetResource()->GetSizeX();
			PassParameters->DestLocationsTex = RT_UAV;
			PassParameters->SourceLocationBuffer = LocationRequestSRV;


			GraphBuilder.AddPass(
				RDG_EVENT_NAME("ShaderWorld LoadReadBacklocations_CS"),
				PassParameters,
				ERDGPassFlags::Compute |
				ERDGPassFlags::NeverCull,
				[PassParameters, ComputeShader, GroupCount](FRHICommandList& RHICmdList)
				{
					FComputeShaderUtils::Dispatch(RHICmdList, ComputeShader, *PassParameters, GroupCount);
				});

		}

	GraphBuilder.Execute();
}

FLoadReadBackLocations_CS

uint SampleDim;
RWTexture2D<float2> DestLocationsTex;
Buffer<float> SourceLocationBuffer;

[numthreads(THREADGROUP_SIZEX, THREADGROUP_SIZEY, THREADGROUP_SIZEZ)]
void SampleLocationLoaderCS(uint3 ThreadId : SV_DispatchThreadID)
{
    if (any(ThreadId.xy >= SampleDim.xx))
        return;

	uint IndexPixel = (ThreadId.x + ThreadId.y * SampleDim) * 2;
	
	DestLocationsTex[ThreadId.xy] = float2(SourceLocationBuffer[IndexPixel],SourceLocationBuffer[IndexPixel + 1]);
}

  • M_Blank_HeightLayer
    • MFC_WorldPositionNormal_Layer
      • M_Blank_HeightLayer未连接
    • MFC_Position_ForCache
  • 其他
    • MF_CacheRead_Reference_Tessellation
    • MFC_CacheRead没有其他引用
    • MFC_CacheRead_Tessellationt
    • MFC_CacheReadNoVertexManipulation
    • MFC_ExternalCacheRead