412 lines
14 KiB
Markdown
412 lines
14 KiB
Markdown
---
|
||
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]);
|
||
}
|
||
```
|
||
|
||
|
||
|
||
#
|
||
- 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 |