--- 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 PendingReads;`。 2. 之后会在USWorldSubsystem::Tick()中调用ShaderWorld::GSWReadbackManager.TickReadBack(),不断检查是否可回读,并进行最终回读。 - 调用顺序:Tick() -> CollisionManagement() -> CollisionGPU() -> UpdateCollisionMeshData() ```c++ namespace ShaderWorld { FORCEINLINE void AsyncReadPixelsFromRT(UShaderWorldRT2D* InRT, TSharedPtr 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 ReadBackStaging = MakeShared(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&>(HeightData), const_cast&>(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 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& Origin, const FSWHeightRetrievalDelegate& Callback) { if (!GeneratorDynamicForReadBack || !SWorldSubsystem) return false; if (!bProcessingHeightRetrieval.IsValid()) { bProcessingHeightRetrieval = MakeShared(); bProcessingHeightRetrieval->AtomicSet(false); } if (!bProcessingHeightRetrievalRT.IsValid()) { bProcessingHeightRetrievalRT = MakeShared(); bProcessingHeightRetrievalRT->AtomicSet(false); } if (!(*bProcessingHeightRetrieval.Get()) && ReadRequestLocation && ReadRequestLocationHeightmap && GeneratorDynamicForReadBack) { bProcessingHeightRetrieval->AtomicSet(true); bProcessingHeightRetrievalRT->AtomicSet(false); HeightRetrieveDelegate = Callback; //初始化采样点数组结构体FSWShareableSamplePoints PointsPendingReadBacks = MakeShared(); TSharedPtr& 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(); 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 ReadBackStaging = MakeShared(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&>(HeightData), const_cast&>(Completion)); } }); HeightReadBackFence.BeginFence(true); } return true; } return false; } ``` ### RequestReadBackLoad ```c++ bool USWorldSubsystem::LoadSampleLocationsInRT(UShaderWorldRT2D* LocationsRequestedRT, TSharedPtr& 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 ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel), PermutationVector); FLoadReadBackLocations_CS::FParameters* PassParameters = GraphBuilder.AllocParameters(); 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 DestLocationsTex; Buffer 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