412 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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个RTReadRequestLocation、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`
- ReadRequestLocationRTF_RG32f初始化于`InitializeReadBackDependencies() <- InitiateWorld()`
- ReadRequestLocationHeightmapRTF_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