---
title: Untitled
date: 2025-06-03 10:19:25
excerpt: 
tags: 
rating: ⭐
---
# 前言
1. ShaderWorldPCGInterop:
2. ShaderWorld:
3. ShaderWorldCore:

# ShaderWorld
- Class 
	- Actor
		- ShaderWorldActor.h:[[#AShaderWorldActor]]
		- SWorld.h:[[#ASWorld]]

## 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~~
	- [x] [[#InitializeReadBackDependencies]]
	- [x] 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()

```c++
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个RT:ReadRequestLocation、ReadRequestLocationHeightmap、GeneratorDynamicForReadBack。
2. 会设置`TObjectPtr < UMaterialInstanceDynamic> GeneratorDynamicForReadBack`各种变量
```c++
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);
```
3. 设置随机种子相关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
- UShaderWorldRT2D(`UTextureRenderTarget2D`)
	- ReadRequestLocation:RTF_RG32f,初始化于`InitializeReadBackDependencies() <- InitiateWorld()`
	- ReadRequestLocationHeightmap:RTF_RGBA8,初始化于`InitializeReadBackDependencies() <- InitiateWorld()`



## 代码
```c++
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
```c++
bool USWorldSubsystem::LoadSampleLocationsInRT(UShaderWorldRT2D* LocationsRequestedRT,
                                               TSharedPtr<FSWShareableSamplePoints>& Samples)
{
	if (!RenderThreadResponded)
		return false;

	const SWSampleRequestComputeData ReadBackData(LocationsRequestedRT, Samples);
	SWToolBox->RequestReadBackLoad(ReadBackData);
	return true;
}
```
# SWShaderToolBox
## RequestReadBackLoad
```c++
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
```c++
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]);
}
```


# FSWDrawMaterial_SL_CS
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>, FSWDrawMaterial_SL_CS, TEXT("/ShaderWorld/ShaderWorldUtilities.usf"), TEXT("DrawMaterialCS"), SF_Compute);

FMeshMaterialShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);  
OutEnvironment.SetDefine(TEXT("SW_DRAW_WITH_HEIGHTNORMAL"), 0);  
OutEnvironment.SetDefine(TEXT("SW_DRAWMATERIAL"), 1);  
OutEnvironment.SetDefine(TEXT("SW_SPECIFIC_LOCATION_DRAW"), 1);  
  
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZEX"), bIsMobileRenderer ? SW_MobileLowSharedMemory_GroupSizeX : FComputeShaderUtils::kGolden2DGroupSize);  
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZEY"), bIsMobileRenderer ? SW_MobileLowSharedMemory_GroupSizeY : FComputeShaderUtils::kGolden2DGroupSize);  
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZEZ"), 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