2337 lines
		
	
	
		
			80 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			2337 lines
		
	
	
		
			80 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]]
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# USWorldSubsystem
							 | 
						|||
| 
								 | 
							
								主要管理:
							 | 
						|||
| 
								 | 
							
								- TArray<USWContextBase*> SW_Contexts 
							 | 
						|||
| 
								 | 
							
								- 渲染相关变量:RT_Ready、RenderThreadPoked、RenderThreadResponded处理。
							 | 
						|||
| 
								 | 
							
								# ASWorld
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# AShaderWorldActor
							 | 
						|||
| 
								 | 
							
								## 大致启动流程
							 | 
						|||
| 
								 | 
							
								大致启动流程:
							 | 
						|||
| 
								 | 
							
								- BeginPlay()
							 | 
						|||
| 
								 | 
							
									1. 设置SWCamera Location。
							 | 
						|||
| 
								 | 
							
									2. 清空所有数据。
							 | 
						|||
| 
								 | 
							
									3. InitiateWorld()
							 | 
						|||
| 
								 | 
							
										1. 更新相关变量:GenerateCollision_last、VerticalRangeMeters_last、WorldHasBounds_OnRebuild。**Segmented_Initialized** 、**bExportPhysicalMaterialID_cached**
							 | 
						|||
| 
								 | 
							
										2. 设置高度生成用材质变量 Generator;bool bHadGeneratorAtRebuildTime = IsValid(Generator);
							 | 
						|||
| 
								 | 
							
										3. LOD_Num与WorldDimensionMeters计算。
							 | 
						|||
| 
								 | 
							
										4. 重新生成若干数组:
							 | 
						|||
| 
								 | 
							
											1. LODs_DimensionsMeters
							 | 
						|||
| 
								 | 
							
											2. ClipMapToUpdateAndMove
							 | 
						|||
| 
								 | 
							
											3. ClipMapToUpdate
							 | 
						|||
| 
								 | 
							
											4. NeedSegmentedUpdate
							 | 
						|||
| 
								 | 
							
											5. AdaptiveTopology
							 | 
						|||
| 
								 | 
							
										5. 相关线程安全变量:
							 | 
						|||
| 
								 | 
							
											1. Shareable_ID_FarLOD
							 | 
						|||
| 
								 | 
							
											2. UpdateHOverTime
							 | 
						|||
| 
								 | 
							
										6. ComputeOptimalVirtualCacheSize()
							 | 
						|||
| 
								 | 
							
										7. for (int32 i = (WorldHasBounds_OnRebuild ? -1 : 0); i < LOD_Num; i++)
							 | 
						|||
| 
								 | 
							
										8. Toggle Async creation of Clipmap Meshes
							 | 
						|||
| 
								 | 
							
										9. Async TaskGraph ClipMapMeshCreation
							 | 
						|||
| 
								 | 
							
								- Tick()
							 | 
						|||
| 
								 | 
							
									- 初始化
							 | 
						|||
| 
								 | 
							
										1. 取得USWorldSubsystem指针,并且进行初始化。
							 | 
						|||
| 
								 | 
							
									- ReadbacksManagement()
							 | 
						|||
| 
								 | 
							
									- CollisionManagement()
							 | 
						|||
| 
								 | 
							
									- SpawnablesManagement()
							 | 
						|||
| 
								 | 
							
									- TerrainAndSpawnablesManagement()
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### ReadbacksManagement()
							 | 
						|||
| 
								 | 
							
								主要用于回读RetrieveHeightAt()调用后GPU计算出来的Position信息。在**用于计算HeightReadBack的渲染线程、RHI、GPU都执行完成**后,从ReadBackHeightData的像素点(最多25个)中读取Z轴信息,之后和PointsPendingReadBacks中的X、Y轴信息合并成一个Vector3 Position。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								- ThreadSafe
							 | 
						|||
| 
								 | 
							
									 - bool
							 | 
						|||
| 
								 | 
							
										 - **bProcessingHeightRetrieval**
							 | 
						|||
| 
								 | 
							
										 - **bProcessingHeightRetrievalRT**
							 | 
						|||
| 
								 | 
							
									 - FSWShareableSamplePoints
							 | 
						|||
| 
								 | 
							
										 - PointsPendingReadBacks
							 | 
						|||
| 
								 | 
							
									 - FSWColorRead
							 | 
						|||
| 
								 | 
							
										 - ReadBackHeightData
							 | 
						|||
| 
								 | 
							
								 - FRenderCommandFence
							 | 
						|||
| 
								 | 
							
									 - HeightReadBackFence
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								void AShaderWorldActor::ReadbacksManagement()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									if (!bProcessingHeightRetrieval.IsValid())
							 | 
						|||
| 
								 | 
							
										bProcessingHeightRetrieval = MakeShared<FThreadSafeBool, ESPMode::ThreadSafe>();
							 | 
						|||
| 
								 | 
							
									if (!bProcessingHeightRetrievalRT.IsValid())
							 | 
						|||
| 
								 | 
							
										bProcessingHeightRetrievalRT = MakeShared<FThreadSafeBool, ESPMode::ThreadSafe>();
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
									//PointsPendingReadBacks存储从GPU回读的采样坐标位置;在RetrieveHeightAt()调用HeightReadBackFence.BeginFence(true)开启渲染栅栏,不开启这段逻辑不会执行。
							 | 
						|||
| 
								 | 
							
									if ((*bProcessingHeightRetrieval.Get()) && (*bProcessingHeightRetrievalRT.Get()) && HeightReadBackFence.IsFenceComplete() && PointsPendingReadBacks.IsValid())
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										// ReadBackHeightData uin8 贴图数据
							 | 
						|||
| 
								 | 
							
										if (!ReadBackHeightData.IsValid())
							 | 
						|||
| 
								 | 
							
											return;
							 | 
						|||
| 
								 | 
							
										
							 | 
						|||
| 
								 | 
							
										//For now we do Compute samples on a rendertarget 5x5, therefore 25 positions evaluated per request.
							 | 
						|||
| 
								 | 
							
										//每次请求可以读取25个点。
							 | 
						|||
| 
								 | 
							
										const int NumOfVertex = 25;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										PositionsOfReadBacks.Empty();
							 | 
						|||
| 
								 | 
							
										PositionsOfReadBacks.AddUninitialized(25);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										uint8* ReadData8 = (uint8*)ReadBackHeightData->ReadData.GetData();
							 | 
						|||
| 
								 | 
							
											uint16 MaterialIndice = 0;
							 | 
						|||
| 
								 | 
							
										for (int32 k = 0; k < NumOfVertex; k++)
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											FVector3f& PositionSample = PositionsOfReadBacks[k];
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											if (RendererAPI == EGeoRenderingAPI::OpenGL)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												int X = k % 5;
							 | 
						|||
| 
								 | 
							
												int Y = k / 5;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												int index = X + Y * 5;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												Y = (5 - 1) - Y;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												index = X + Y * 5;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												PositionSample = FVector3f(PointsPendingReadBacks->PositionsXY[2 * k], PointsPendingReadBacks->PositionsXY[2 * k + 1], GetHeightFromGPURead(&ReadData8[index * 4], MaterialIndice) / HeightScale);
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
											else
							 | 
						|||
| 
								 | 
							
												PositionSample = FVector3f(PointsPendingReadBacks->PositionsXY[2 * k], PointsPendingReadBacks->PositionsXY[2 * k + 1], GetHeightFromGPURead(&ReadData8[k * 4], MaterialIndice) / HeightScale);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										if(HeightRetrieveDelegate.ExecuteIfBound(PositionsOfReadBacks))
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											//SW_LOG("HeightRetrieveDelegate.ExecuteIfBound(PositionsOfReadBacks) PositionsOfReadBacks[0] %s",*PositionsOfReadBacks[0].ToString())
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
										else
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											//SW_LOG("Fail HeightRetrieveDelegate.ExecuteIfBound(PositionsOfReadBacks)")
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										bProcessingHeightRetrieval->AtomicSet(false);
							 | 
						|||
| 
								 | 
							
										bProcessingHeightRetrievalRT->AtomicSet(false);
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//For now MinMax is here
							 | 
						|||
| 
								 | 
							
									//处理FClipMapMeshElement的最大最小队列?
							 | 
						|||
| 
								 | 
							
									if (UseSegmented())
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										if(WorldHasBounds_OnRebuild)
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											FClipMapMeshElement& MeshEl = FarLOD_BoundedWorld;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											if (MeshEl.MinMaxQueue.Num() > 0)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												MeshEl.ProcessMinMaxQueue(SWorldSubsystem);
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
										
							 | 
						|||
| 
								 | 
							
										for (FClipMapMeshElement& MeshEl : Meshes)
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											if (MeshEl.MinMaxQueue.Num() > 0)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												MeshEl.ProcessMinMaxQueue(SWorldSubsystem);
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### CollisionManagement()
							 | 
						|||
| 
								 | 
							
								- ThreadSafe
							 | 
						|||
| 
								 | 
							
									 - bool
							 | 
						|||
| 
								 | 
							
										 - ***bProcessingGroundCollision***:处理地面碰撞。
							 | 
						|||
| 
								 | 
							
										 - bPreprocessingCollisionUpdate
							 | 
						|||
| 
								 | 
							
										 - EditRebuild:传递Bool值给 rebuild。
							 | 
						|||
| 
								 | 
							
									 - FSWCollisionManagementShareableData
							 | 
						|||
| 
								 | 
							
										 - CollisionShareable
							 | 
						|||
| 
								 | 
							
								 - FRenderCommandFence
							 | 
						|||
| 
								 | 
							
									- 1
							 | 
						|||
| 
								 | 
							
								- bool 
							 | 
						|||
| 
								 | 
							
									- RedbuildCollisionContext
							 | 
						|||
| 
								 | 
							
								- Array
							 | 
						|||
| 
								 | 
							
									- CollisionReadToProcess:
							 | 
						|||
| 
								 | 
							
									- CollisionWorkQueue:类型为FCollisionProcessingWork,碰撞处理任务队列,将回读的
							 | 
						|||
| 
								 | 
							
								- FCollisionMeshElement
							 | 
						|||
| 
								 | 
							
									- ReadBackCompletion:碰撞数据GPU回读是否完成。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								相关条件
							 | 
						|||
| 
								 | 
							
								if ((*bPreprocessingCollisionUpdate.Get()) ||  
							 | 
						|||
| 
								 | 
							
								    CollisionShareable->CollisionMeshToUpdate.Num() > 0 ||  
							 | 
						|||
| 
								 | 
							
								    CollisionShareable->CollisionMeshToRenameMoveUpdate.Num() > 0 ||  
							 | 
						|||
| 
								 | 
							
								    CollisionShareable->CollisionMeshToCreate.Num() > 0)  
							 | 
						|||
| 
								 | 
							
								    return;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (CollisionUpdateTimeAcu <= 1.f / 10.f || CollisionWorkQueue.Num() > 0 || !CollisionProcess.IsFenceComplete())
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								void AShaderWorldActor::CollisionManagement(float& DeltaT)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									SCOPED_NAMED_EVENT_TEXT("AShaderWorldActor::CollisionManagement", FColor::Magenta);
							 | 
						|||
| 
								 | 
							
									SW_FCT_CYCLE()
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									/*
							 | 
						|||
| 
								 | 
							
									 * Can we execute compute shader?
							 | 
						|||
| 
								 | 
							
									 * Do we need to rebuild collision?
							 | 
						|||
| 
								 | 
							
									 * Did ShaderWorld toggled collision generation On/Off?
							 | 
						|||
| 
								 | 
							
									 * Are we pending a full rebuild of the Shader World?
							 | 
						|||
| 
								 | 
							
									 */
							 | 
						|||
| 
								 | 
							
									if (!SetupCollisions())
							 | 
						|||
| 
								 | 
							
										return;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									/*
							 | 
						|||
| 
								 | 
							
									 * Using collision updates, update Collision meshes
							 | 
						|||
| 
								 | 
							
									 */
							 | 
						|||
| 
								 | 
							
									if (!CollisionFinalizeWork())
							 | 
						|||
| 
								 | 
							
										return;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (CollisionProcess.IsFenceComplete())
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										/*
							 | 
						|||
| 
								 | 
							
										 * Convert Compute shader results to actionable collision updates
							 | 
						|||
| 
								 | 
							
										 */
							 | 
						|||
| 
								 | 
							
										if (!CollisionPreprocessGPU())
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											CollisionProcess.BeginFence(true);
							 | 
						|||
| 
								 | 
							
											return;
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									/*
							 | 
						|||
| 
								 | 
							
									 * Process GPU work queue by launching GPU tasks to evaluate the collision of new tiles
							 | 
						|||
| 
								 | 
							
									 */
							 | 
						|||
| 
								 | 
							
									CollisionGPU();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Timer
							 | 
						|||
| 
								 | 
							
									// 碰撞生成与Update计时
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										CollisionUpdateTimeAcu += DeltaT;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										//CollisionUpdateTimeAcu如果超过0.1s,或者CollisionWorkQueue的任务都完成了。CollisionProcess已经完成。
							 | 
						|||
| 
								 | 
							
										if (CollisionUpdateTimeAcu <= 1.f / 10.f || CollisionWorkQueue.Num() > 0 || !CollisionProcess.IsFenceComplete())
							 | 
						|||
| 
								 | 
							
											return;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										CollisionUpdateTimeAcu = 0.f;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									/*
							 | 
						|||
| 
								 | 
							
									 * Gather relevant collision tiles
							 | 
						|||
| 
								 | 
							
									 * If an old tile is not relevant anymore, release it.
							 | 
						|||
| 
								 | 
							
									 * If a new location needs to be computed: allocate a tile and add its relevant computation work to the GPU work queue
							 | 
						|||
| 
								 | 
							
									 */
							 | 
						|||
| 
								 | 
							
									CollisionCPU();
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#### SetupCollisions()
							 | 
						|||
| 
								 | 
							
								设置相关变量。
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								bool AShaderWorldActor::SetupCollisions()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									SW_FCT_CYCLE()
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (!bHadGeneratorAtRebuildTime)
							 | 
						|||
| 
								 | 
							
										return false;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (!Shareable_ID.IsValid() || Meshes.Num() <= 0)
							 | 
						|||
| 
								 | 
							
										return false;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//初始化线程安全变量
							 | 
						|||
| 
								 | 
							
									if (!bProcessingGroundCollision.IsValid())
							 | 
						|||
| 
								 | 
							
										bProcessingGroundCollision = MakeShared<FThreadSafeBool, ESPMode::ThreadSafe>();
							 | 
						|||
| 
								 | 
							
									if (!bPreprocessingCollisionUpdate.IsValid())
							 | 
						|||
| 
								 | 
							
										bPreprocessingCollisionUpdate = MakeShared<FThreadSafeBool, ESPMode::ThreadSafe>();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (EditRebuild)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										EditRebuild.AtomicSet(false);
							 | 
						|||
| 
								 | 
							
										rebuild = true;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (rebuild)
							 | 
						|||
| 
								 | 
							
										RedbuildCollisionContext = true;
							 | 
						|||
| 
								 | 
							
									//重建相关变量初始化
							 | 
						|||
| 
								 | 
							
									if (RedbuildCollisionContext)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										if (!(*bProcessingGroundCollision.Get()) && !(*bPreprocessingCollisionUpdate.Get())
							 | 
						|||
| 
								 | 
							
											&& CollisionProcess.IsFenceComplete()
							 | 
						|||
| 
								 | 
							
											&& (CollisionMesh.Num() <= 0)
							 | 
						|||
| 
								 | 
							
											&& (UsedCollisionMesh.Num() <= 0))
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											CollisionShareable = nullptr;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											CollisionWorkQueue.Empty();
							 | 
						|||
| 
								 | 
							
											CollisionReadToProcess.Empty();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											RedbuildCollisionContext = false;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (RedbuildCollisionContext)
							 | 
						|||
| 
								 | 
							
										return false;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (!GenerateCollision)
							 | 
						|||
| 
								 | 
							
										return false;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//创建全线程碰撞生成相关数据结构体CollisionShareable
							 | 
						|||
| 
								 | 
							
									if (!CollisionShareable.IsValid())
							 | 
						|||
| 
								 | 
							
										CollisionShareable = MakeShared<FSWCollisionManagementShareableData, ESPMode::ThreadSafe>(CollisionResolution, CollisionVerticesPerPatch);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if ((*bProcessingGroundCollision.Get()) || (*bPreprocessingCollisionUpdate.Get()) || !CameraSet || (Meshes.Num() == 0))
							 | 
						|||
| 
								 | 
							
										return false;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//Let the data layer be computed before generating collisions and trying to extract material IDs
							 | 
						|||
| 
								 | 
							
									if (bExportPhysicalMaterialID && (WorldCycle < 2))
							 | 
						|||
| 
								 | 
							
										return false;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (CollisionVisibleChanged)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										if (GetWorld())
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											for (auto& ColM : CollisionMesh)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												if (auto& Mesh = ColM.Value.Mesh)
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													Mesh->SetMeshSectionVisible(0, CollisionVisible);
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
										CollisionVisibleChanged.AtomicSet(false);
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									return true;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#### CollisionFinalizeWork() 笔记为3.8.6版本非最新
							 | 
						|||
| 
								 | 
							
								结束碰撞生成任务,true为完成,false为任务超时未完成。**主要的逻辑是将之前的数据设置为脏,并且更新FShaderWProceduralMeshSceneProxy,5.4 Finaly版本里这里已经移除了碰撞相关逻辑**
							 | 
						|||
| 
								 | 
							
								- TMap<FName,FCollisionMeshElement> CollisionMesh:碰撞Name => 碰撞Mesh Map。
							 | 
						|||
| 
								 | 
							
									- FCollisionMeshElement:管理单个碰撞数据的结构体。
							 | 
						|||
| 
								 | 
							
								- UBodySetup:虚幻引擎中一个重要的物理相关类,主要用于定义和存储物体的物理属性和碰撞设置
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								bool AShaderWorldActor::CollisionFinalizeWork()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									SCOPED_NAMED_EVENT_TEXT("AShaderWorldActor::CollisionFinalizeWork()", FColor::Magenta);
							 | 
						|||
| 
								 | 
							
									SW_FCT_CYCLE()
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
									if (!CollisionReadToProcess.IsEmpty())
							 | 
						|||
| 
								 | 
							
										return true;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									const double GameThreadBudget_ms = SWGameThreadBudgetCollision_ms.GetValueOnGameThread();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									double TimeStart = FPlatformTime::Seconds();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//判断处理队列是否为空
							 | 
						|||
| 
								 | 
							
									if(CollisionWorkQueue.Num()<=0)
							 | 
						|||
| 
								 | 
							
										return true;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										FScopeLock CollisionMeshArrayAccess(&CollisionMeshAccessLock);
							 | 
						|||
| 
								 | 
							
										for (int i = CollisionWorkQueue.Num() - 1; i >= 0; i--)
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											//判断生成时间是否是否超过预设数值,如果超过就直接返回。默认为1 ms。
							 | 
						|||
| 
								 | 
							
											if ((FPlatformTime::Seconds() - TimeStart) * 1000.0 > GameThreadBudget_ms)
							 | 
						|||
| 
								 | 
							
												return false;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											//将生成的碰撞数据赋予给对应的碰撞Mesh,最后移除任务队列中的任务。
							 | 
						|||
| 
								 | 
							
											FCollisionProcessingWork& Work = CollisionWorkQueue[i];
							 | 
						|||
| 
								 | 
							
											ensure(CollisionMesh.Find(Work.MeshID));
							 | 
						|||
| 
								 | 
							
											FCollisionMeshElement& Mesh = CollisionMesh[Work.MeshID];
							 | 
						|||
| 
								 | 
							
											Mesh.Mesh->UpdateSectionTriMesh(Work.DestB);
							 | 
						|||
| 
								 | 
							
											CollisionWorkQueue.RemoveAt(i);
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									CollisionWorkQueue.Empty();
							 | 
						|||
| 
								 | 
							
									return true;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void UShaderWorldCollisionComponent::UpdateSectionTriMesh(TSharedPtr<FSWShareableVerticePositionBuffer, ESPMode::ThreadSafe>& Positions)
							 | 
						|||
| 
								 | 
							
								{	
							 | 
						|||
| 
								 | 
							
									//当UBodySetup更新队列还有任务时,执行改函数会将FSWShareableVerticePositionBuffer加入到UpdatesReceivedDuringCompute数组中并且退出。
							 | 
						|||
| 
								 | 
							
									if (AsyncBodySetupQueue.Num() > 0)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
								#if SWDEBUG
							 | 
						|||
| 
								 | 
							
										SW_LOG("Collision Update received during alreayd occuring computation %s",*GetName())
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										UpdatesReceivedDuringCompute.Add(Positions);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										return;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
									UpdatesReceivedDuringCompute.Empty();
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
									//使用FSWShareableVerticePositionBuffer数据来更新当前UShaderWorldCollisionComponent
							 | 
						|||
| 
								 | 
							
									bool EnsureSameBuffers = ProcMeshSections.Num() > 0 && ProcMeshSections[0].PositionBuffer.IsValid() && (ProcMeshSections[0].PositionBuffer->Positions3f.Num() == 0 || ProcMeshSections[0].PositionBuffer->Positions3f.Num() == Positions->Positions.Num());
							 | 
						|||
| 
								 | 
							
									if(!EnsureSameBuffers)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
								#if SWDEBUG
							 | 
						|||
| 
								 | 
							
										UE_LOG(LogTemp,Warning,TEXT("Error UpdateSectionTriMesh : buffers incompatible"));
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									else
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										ProcMeshSections[0].PositionBuffer.Reset();
							 | 
						|||
| 
								 | 
							
										ProcMeshSections[0].Normals.Reset();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										ProcMeshSections[0].PositionBuffer = Positions;
							 | 
						|||
| 
								 | 
							
										ProcMeshSections[0].SectionLocalBox = Positions->Bound;
							 | 
						|||
| 
								 | 
							
										ProcMeshSections[0].bEnableCollision = true;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										Async(EAsyncExecution::TaskGraph, [WeakThis = MakeWeakObjectPtr(this), PBuffer = Positions, IndexB = ProcMeshSections[0].IndexBuffer]
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
												TSharedPtr<TArray<FVector>, ESPMode::ThreadSafe> Normals = SWComputeNormalsForPatch(PBuffer, IndexB);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												AsyncTask(ENamedThreads::GameThread, [WeakThis,PBuffer, Normals]()
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
														if (WeakThis.IsValid())
							 | 
						|||
| 
								 | 
							
														{
							 | 
						|||
| 
								 | 
							
															if (UShaderWorldCollisionComponent* Comp = Cast<UShaderWorldCollisionComponent>(WeakThis.Get()))
							 | 
						|||
| 
								 | 
							
															{
							 | 
						|||
| 
								 | 
							
																//塞入Normal
							 | 
						|||
| 
								 | 
							
																if(IsValid(Comp))
							 | 
						|||
| 
								 | 
							
																	Comp->ReceiveComputedNormals(PBuffer, Normals);
							 | 
						|||
| 
								 | 
							
															}
							 | 
						|||
| 
								 | 
							
														}
							 | 
						|||
| 
								 | 
							
												});
							 | 
						|||
| 
								 | 
							
										});
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
									//Materials
							 | 
						|||
| 
								 | 
							
									// Pass new positions to trimesh
							 | 
						|||
| 
								 | 
							
									UpdateCollision();//1. 异步Cook UBodySetup 2. 删除原本的碰撞 3. UseBodySetup->CreatePhysicsMeshesAsync(),使用UBodySetup异步创建新的碰撞网格。
							 | 
						|||
| 
								 | 
							
									UpdateLocalBounds();//更新UShaderWorldCollisionComponent的LocalBoundingBox
							 | 
						|||
| 
								 | 
							
									UpdateNavigation();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (ProcMeshSections.Num() > 0 && (ProcMeshSections[0].bSectionVisible || (GetWorld() && !GetWorld()->IsGameWorld())))
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										// If we have a valid proxy and it is not pending recreation
							 | 
						|||
| 
								 | 
							
										if (SceneProxy && !IsRenderStateDirty())
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											//SW_LOG("Update trimesh SceneProxy && !IsRenderStateDirty()")
							 | 
						|||
| 
								 | 
							
											// Create data to update section
							 | 
						|||
| 
								 | 
							
											FShaderWColProcMeshSectionUpdateData* SectionData = new FShaderWColProcMeshSectionUpdateData;
							 | 
						|||
| 
								 | 
							
											SectionData->TargetSection = 0;
							 | 
						|||
| 
								 | 
							
											SectionData->NewPositionBuffer = ProcMeshSections[0].PositionBuffer;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											//更新SceneProxy FShaderWProceduralMeshSceneProxy的NewPositionBuffer,也就是UpdateSection
							 | 
						|||
| 
								 | 
							
											if(AShaderWorldActor* owner = Cast<AShaderWorldActor>(GetOwner()))
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													// Enqueue command to send to render thread
							 | 
						|||
| 
								 | 
							
													FShaderWProceduralMeshSceneProxy* ProcMeshSceneProxy = (FShaderWProceduralMeshSceneProxy*)(SceneProxy && !IsRenderStateDirty() ? SceneProxy : nullptr);
							 | 
						|||
| 
								 | 
							
													ENQUEUE_RENDER_COMMAND(FGeoCProcMeshSectionUpdate)
							 | 
						|||
| 
								 | 
							
														([ProcMeshSceneProxy, SectionData](FRHICommandListImmediate& RHICmdList)
							 | 
						|||
| 
								 | 
							
														{
							 | 
						|||
| 
								 | 
							
															if(ProcMeshSceneProxy)
							 | 
						|||
| 
								 | 
							
																ProcMeshSceneProxy->UpdateSection_RenderThread(SectionData);
							 | 
						|||
| 
								 | 
							
														});
							 | 
						|||
| 
								 | 
							
												}				
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
											else
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												//SW_LOG("Update trimesh !owner")
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
										else
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											//SW_LOG("Update trimesh !(SceneProxy && !IsRenderStateDirty())")
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										MarkRenderTransformDirty();
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#### CollisionPreprocessGPU()
							 | 
						|||
| 
								 | 
							
								GPU生成碰撞 的预处理阶段。
							 | 
						|||
| 
								 | 
							
								将从GPU回读的碰撞顶点Z轴数据***uint8* ReadData8*** 反序列化成double,之后再还原成***FCollisionProcessingWork.DestB***的Positions、Normals、Positions3f、MaterialIndices、Bound。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								bool AShaderWorldActor::CollisionPreprocessGPU()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									SCOPED_NAMED_EVENT_TEXT("AShaderWorldActor::CollisionPreprocessGPU()", FColor::Magenta);
							 | 
						|||
| 
								 | 
							
									SW_FCT_CYCLE()
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									for (int32 CollID = CollisionReadToProcess.Num() - 1; CollID >= 0; CollID--)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										const FName& ElID = CollisionReadToProcess[CollID];
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										if (!CollisionMesh.Find(ElID))
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											CollisionWorkQueue.Empty();
							 | 
						|||
| 
								 | 
							
											CollisionReadToProcess.RemoveAt(CollID);
							 | 
						|||
| 
								 | 
							
											continue;
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										//判断FCollisionMeshElement是否有效,以及是否将碰撞数据回读完成,如果完成,则将数据添加到碰撞处理队列CollisionWorkQueue,并且从碰撞回读队列CollisionReadToProcess
							 | 
						|||
| 
								 | 
							
										FCollisionMeshElement& Mesh = *CollisionMesh.Find(ElID);
							 | 
						|||
| 
								 | 
							
										if ((*Mesh.ReadBackCompletion.Get()))
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											ensure(Mesh.Mesh);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											if(FGeoCProcMeshSection* Section = Mesh.Mesh->GetProcMeshSection(0))
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												if(CollisionMesh.Contains(CollisionBufferHolder))
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													CollisionWorkQueue.Emplace(
							 | 
						|||
| 
								 | 
							
														ElID
							 | 
						|||
| 
								 | 
							
														, Mesh.HeightData
							 | 
						|||
| 
								 | 
							
														, (*CollisionMesh.Find(CollisionBufferHolder)).Mesh->VerticesTemplate
							 | 
						|||
| 
								 | 
							
														, (*CollisionMesh.Find(CollisionBufferHolder)).Mesh->TrianglesTemplate);
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
												else
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													SW_LOG("!CollisionMesh.Contains(CollisionBufferHolder)")
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
											else
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												SW_LOG("CollisionPreprocessGPU :: Mesh.Mesh->GetProcMeshSection(0) = nullptr")
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
											
							 | 
						|||
| 
								 | 
							
											CollisionReadToProcess.RemoveAt(CollID);
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									//回读队列处理完毕后之后执行后续逻辑
							 | 
						|||
| 
								 | 
							
									if (!CollisionReadToProcess.IsEmpty())
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										return false;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//开始执行碰撞处理队列逻辑
							 | 
						|||
| 
								 | 
							
									CollisionReadToProcess.Empty();
							 | 
						|||
| 
								 | 
							
									if (CollisionWorkQueue.Num() > 0)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										(*bProcessingGroundCollision.Get()) = true;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										AShaderWorldActor* SWContext = this;
							 | 
						|||
| 
								 | 
							
										//异步并行 反序列化Ground碰撞数据
							 | 
						|||
| 
								 | 
							
										Async(EAsyncExecution::TaskGraph, [Completion = bProcessingGroundCollision, RenderAPI = RendererAPI, VerticesPerPatch = CollisionVerticesPerPatch, Work = CollisionWorkQueue]
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												ParallelFor(Work.Num(), [&](int32 WorkIndex)
							 | 
						|||
| 
								 | 
							
													{						
							 | 
						|||
| 
								 | 
							
														
							 | 
						|||
| 
								 | 
							
														const FCollisionProcessingWork& WorkEl = Work[WorkIndex];
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														if (!WorkEl.Read.IsValid() || !WorkEl.SourceB.IsValid() || !WorkEl.DestB.IsValid())
							 | 
						|||
| 
								 | 
							
															return;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														const int NumOfVertex = WorkEl.SourceB->Positions.Num();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														WorkEl.DestB->Positions.SetNum(NumOfVertex);
							 | 
						|||
| 
								 | 
							
														WorkEl.DestB->Positions3f.SetNum(NumOfVertex);
							 | 
						|||
| 
								 | 
							
														WorkEl.DestB->MaterialIndices.SetNum(NumOfVertex);
							 | 
						|||
| 
								 | 
							
														WorkEl.DestB->Bound = FBox(EForceInit::ForceInit);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														FVector LocationfVertice_WS(0);
							 | 
						|||
| 
								 | 
							
														uint16 MaterialIndice = 0;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														//取得从GPU回读的序列化数据
							 | 
						|||
| 
								 | 
							
														uint8* ReadData8 = (uint8*)WorkEl.Read->ReadData.GetData();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														TSet<int32>& TrianglesAffectedByHoles = WorkEl.DestB->TrianglesAffectedByHoles;
							 | 
						|||
| 
								 | 
							
														TrianglesAffectedByHoles.Empty();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														//#TODO ISPC slower ?
							 | 
						|||
| 
								 | 
							
								#if 0 // INTEL_ISPC
							 | 
						|||
| 
								 | 
							
															if (RenderAPI == EGeoRenderingAPI::OpenGL)
							 | 
						|||
| 
								 | 
							
															{
							 | 
						|||
| 
								 | 
							
																ispc::ShaderWorld_HeightFromGPUReadOpenGL(NumOfVertex, VerticesPerPatch, ReadData8,(ispc::FVector*)WorkEl.SourceB->Positions.GetData(), (ispc::FVector*)WorkEl.DestB->Positions.GetData(), (ispc::FVector3f*)WorkEl.DestB->Positions3f.GetData(), WorkEl.DestB->MaterialIndices.GetData());
							 | 
						|||
| 
								 | 
							
																
							 | 
						|||
| 
								 | 
							
															}
							 | 
						|||
| 
								 | 
							
															else
							 | 
						|||
| 
								 | 
							
															{
							 | 
						|||
| 
								 | 
							
																ispc::ShaderWorld_HeightFromGPURead(NumOfVertex, VerticesPerPatch, ReadData8, (ispc::FVector3f*)WorkEl.SourceB->Positions3f.GetData(), (ispc::FVector*)WorkEl.DestB->Positions.GetData(), (ispc::FVector3f*)WorkEl.DestB->Positions3f.GetData(), WorkEl.DestB->MaterialIndices.GetData());
							 | 
						|||
| 
								 | 
							
															}
							 | 
						|||
| 
								 | 
							
								#else
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														//从对序列化碰撞Z轴数据进行反序列化,还原成double,再之后还原成FCollisionProcessingWork.DestB
							 | 
						|||
| 
								 | 
							
														for (int32 k = 0; k < NumOfVertex; k++)
							 | 
						|||
| 
								 | 
							
															{
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
																if (RenderAPI == EGeoRenderingAPI::OpenGL)
							 | 
						|||
| 
								 | 
							
																{
							 | 
						|||
| 
								 | 
							
																	const int index = k % VerticesPerPatch + (VerticesPerPatch - 1 - (k / VerticesPerPatch)) * VerticesPerPatch;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
																	LocationfVertice_WS = FVector(WorkEl.SourceB->Positions[k].X, WorkEl.SourceB->Positions[k].Y, GetHeightFromGPURead(&ReadData8[4 * index], MaterialIndice));
							 | 
						|||
| 
								 | 
							
																}
							 | 
						|||
| 
								 | 
							
																else
							 | 
						|||
| 
								 | 
							
																	LocationfVertice_WS = FVector(WorkEl.SourceB->Positions[k].X, WorkEl.SourceB->Positions[k].Y, GetHeightFromGPURead(&ReadData8[4 * k], MaterialIndice));
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
																WorkEl.DestB->Positions[k] = LocationfVertice_WS;
							 | 
						|||
| 
								 | 
							
																WorkEl.DestB->Positions3f[k] = FVector3f(LocationfVertice_WS);
							 | 
						|||
| 
								 | 
							
																WorkEl.DestB->MaterialIndices[k] = MaterialIndice;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
																
							 | 
						|||
| 
								 | 
							
																/*
							 | 
						|||
| 
								 | 
							
																 * Height below -7km means terrain hole
							 | 
						|||
| 
								 | 
							
																 */
							 | 
						|||
| 
								 | 
							
																if(WorkEl.DestB->Positions[k].Z < -700000.0)
							 | 
						|||
| 
								 | 
							
																{
							 | 
						|||
| 
								 | 
							
																	/*
							 | 
						|||
| 
								 | 
							
																	 * Find triangles including this vertex and add them to removed triangles
							 | 
						|||
| 
								 | 
							
																	 */
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
																	if(WorkEl.SourceB->PositionToTriangle.Contains(k))
							 | 
						|||
| 
								 | 
							
																	{
							 | 
						|||
| 
								 | 
							
																		TrianglesAffectedByHoles.Append(*WorkEl.SourceB->PositionToTriangle.Find(k));
							 | 
						|||
| 
								 | 
							
																	}
							 | 
						|||
| 
								 | 
							
																}
							 | 
						|||
| 
								 | 
							
																else
							 | 
						|||
| 
								 | 
							
																{
							 | 
						|||
| 
								 | 
							
																	WorkEl.DestB->Bound += WorkEl.DestB->Positions[k];
							 | 
						|||
| 
								 | 
							
																}
							 | 
						|||
| 
								 | 
							
															}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
														/*
							 | 
						|||
| 
								 | 
							
														 * If the terrain has holes, create a custom index buffer with the related triangles removed
							 | 
						|||
| 
								 | 
							
														 * 地形挖洞,碰撞逻辑处理。
							 | 
						|||
| 
								 | 
							
														 */
							 | 
						|||
| 
								 | 
							
														if(TrianglesAffectedByHoles.Num() > 0)
							 | 
						|||
| 
								 | 
							
														{
							 | 
						|||
| 
								 | 
							
															WorkEl.DestB->FilteredTriangles = MakeShared<FSWShareableIndexBuffer, ESPMode::ThreadSafe>();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
															for(int32 Triangle = 0; Triangle < WorkEl.TriangleTemplate->Indices.Num()/3; Triangle++)
							 | 
						|||
| 
								 | 
							
															{
							 | 
						|||
| 
								 | 
							
																if(!TrianglesAffectedByHoles.Contains(Triangle))
							 | 
						|||
| 
								 | 
							
																{
							 | 
						|||
| 
								 | 
							
																	WorkEl.DestB->FilteredTriangles->Indices.Add(WorkEl.TriangleTemplate->Indices[Triangle * 3]);
							 | 
						|||
| 
								 | 
							
																	WorkEl.DestB->FilteredTriangles->Indices.Add(WorkEl.TriangleTemplate->Indices[Triangle * 3 + 1]);
							 | 
						|||
| 
								 | 
							
																	WorkEl.DestB->FilteredTriangles->Indices.Add(WorkEl.TriangleTemplate->Indices[Triangle * 3 + 2]);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
																	WorkEl.DestB->FilteredTriangles->Triangles_CollisionOnly.Add(WorkEl.TriangleTemplate->Triangles_CollisionOnly[Triangle]);
							 | 
						|||
| 
								 | 
							
																}
							 | 
						|||
| 
								 | 
							
															}
							 | 
						|||
| 
								 | 
							
														}
							 | 
						|||
| 
								 | 
							
														else
							 | 
						|||
| 
								 | 
							
														{
							 | 
						|||
| 
								 | 
							
															WorkEl.DestB->FilteredTriangles.Reset();
							 | 
						|||
| 
								 | 
							
														}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														//WorkEl.DestB->Bound = FBox(WorkEl.DestB->Positions);
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
												);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												//执行完成后将Completion(bProcessingGroundCollision)设置为false代表处理完成。
							 | 
						|||
| 
								 | 
							
												if (Completion.IsValid())
							 | 
						|||
| 
								 | 
							
													Completion->AtomicSet(false);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											});
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									return true;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								#### CollisionGPU()
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void AShaderWorldActor::CollisionGPU()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									SCOPED_NAMED_EVENT_TEXT("AShaderWorldActor::CollisionGPU()", FColor::Magenta);
							 | 
						|||
| 
								 | 
							
									SW_FCT_CYCLE()
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									double CurrentTime = FPlatformTime::Seconds();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										if (!(!(*bPreprocessingCollisionUpdate.Get()) && (
							 | 
						|||
| 
								 | 
							
											CollisionShareable->CollisionMeshToUpdate.Num() > 0 ||
							 | 
						|||
| 
								 | 
							
											CollisionShareable->CollisionMeshToRenameMoveUpdate.Num() > 0 ||
							 | 
						|||
| 
								 | 
							
											CollisionShareable->CollisionMeshToCreate.Num() > 0)))
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											/*
							 | 
						|||
| 
								 | 
							
											 * No collision Preprocessing running, we can safely access the data in the shared pointer without risking race condition
							 | 
						|||
| 
								 | 
							
											 * 确保没有PreprocessingCollision任务在运行
							 | 
						|||
| 
								 | 
							
											 */
							 | 
						|||
| 
								 | 
							
											if(!(*bPreprocessingCollisionUpdate.Get()))
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												FScopeLock CollisionMeshArrayAccess(CollisionMeshAccessLock.Get());
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												TArray<FName> NameToRemove;
							 | 
						|||
| 
								 | 
							
												//遍历AvailableCollisionMesh
							 | 
						|||
| 
								 | 
							
												for (const FName& AvailableID : CollisionShareable->AvailableCollisionMesh)
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													FCollisionMeshElement& Elem = *CollisionMesh.Find(AvailableID);
							 | 
						|||
| 
								 | 
							
													//更新时间戳
							 | 
						|||
| 
								 | 
							
													if (Elem.SleepTime < 0.0)
							 | 
						|||
| 
								 | 
							
														Elem.SleepTime = CurrentTime;
							 | 
						|||
| 
								 | 
							
													else if ((abs(CurrentTime - Elem.SleepTime) >= 1.0) && (CollisionBufferHolder == "" || AvailableID != CollisionBufferHolder) && (!Elem.Mesh || (Elem.Mesh && !Elem.Mesh->HasAsyncWorkPending())))//如果生成超时,则销毁对应变量
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														if (IsValid(Elem.Mesh))						
							 | 
						|||
| 
								 | 
							
															Elem.Mesh->DestroyComponent();							
							 | 
						|||
| 
								 | 
							
														
							 | 
						|||
| 
								 | 
							
														Elem.Mesh = nullptr;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														DecountRTAllocatedMemory(Elem.CollisionRT)
							 | 
						|||
| 
								 | 
							
														DecountRTAllocatedMemory(Elem.CollisionRT_Duplicate)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														Elem.CollisionRT = nullptr;
							 | 
						|||
| 
								 | 
							
														Elem.CollisionRT_Duplicate = nullptr;
							 | 
						|||
| 
								 | 
							
														Elem.DynCollisionCompute = nullptr;
							 | 
						|||
| 
								 | 
							
														Elem.LayerComputeForPhysicalMaterial.Empty();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														CollisionMesh.Remove(AvailableID);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														if (UsedCollisionMesh.Contains(AvailableID))
							 | 
						|||
| 
								 | 
							
														{
							 | 
						|||
| 
								 | 
							
															UsedCollisionMesh.Remove(AvailableID);
							 | 
						|||
| 
								 | 
							
														}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														CollisionShareable->CollisionMeshData.Remove(AvailableID);
							 | 
						|||
| 
								 | 
							
														CollisionShareable->UsedCollisionMesh.Remove(AvailableID);
							 | 
						|||
| 
								 | 
							
														NameToRemove.Add(AvailableID);
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
													else
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
												for (auto& TR : NameToRemove)
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													CollisionShareable->AvailableCollisionMesh.Remove(TR);
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											return;
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
											
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									UWorld* World = GetWorld();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									bool RequireRenderFence = false;
							 | 
						|||
| 
								 | 
							
									int32 CollisionDrawCallCount = 0;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									UsedCollisionMesh = CollisionShareable->UsedCollisionMesh;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									/*
							 | 
						|||
| 
								 | 
							
									 * Async task created proxy CollisionMesh and associated IDs to them, create actual GameThread collision using the provided IDs
							 | 
						|||
| 
								 | 
							
									 * 异步任务创建了代理碰撞网格,并将相关 ID 与它们关联起来,使用提供的 ID 在游戏线程中创建实际的碰撞。
							 | 
						|||
| 
								 | 
							
									 */
							 | 
						|||
| 
								 | 
							
									for (FName& ID : CollisionShareable->CollisionMeshToCreate)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										//使用需要创建碰撞的ID(Name)来获取碰撞MeshData.
							 | 
						|||
| 
								 | 
							
										const FSWCollisionMeshElemData& Mesh_Shareable = *CollisionShareable->CollisionMeshData.Find(ID);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										FCollisionMeshElement& Mesh = GetACollisionMesh(ID);//GetACollisionMesh()取得现有FCollisionMeshElement或者创建新的,代码贼长。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										Mesh.Location = Mesh_Shareable.Location;
							 | 
						|||
| 
								 | 
							
										Mesh.MeshLocation = Mesh_Shareable.MeshLocation;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										Mesh.Mesh->SetWorldTransform(FTransform(Mesh_Shareable.MeshLocation));
							 | 
						|||
| 
								 | 
							
										Mesh.Mesh->SetCollisionProfileName(UCollisionProfile::BlockAll_ProfileName);
							 | 
						|||
| 
								 | 
							
										Mesh.Mesh->Mobility = EComponentMobility::Static;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//清空创建列表。
							 | 
						|||
| 
								 | 
							
									CollisionShareable->CollisionMeshToCreate.Empty();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//处理CollisionMeshToUpdate 碰撞数据更新队列
							 | 
						|||
| 
								 | 
							
									for (int i = CollisionShareable->CollisionMeshToUpdate.Num() - 1; i >= 0; i--)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										FName& CollisionIDToUpdate = CollisionShareable->CollisionMeshToUpdate[i];
							 | 
						|||
| 
								 | 
							
										FCollisionMeshElement& El = *CollisionMesh.Find(CollisionIDToUpdate);
							 | 
						|||
| 
								 | 
							
										UpdateCollisionMeshData(El);//核心函数
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										CollisionShareable->CollisionMeshToUpdate.RemoveAt(i);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										RequireRenderFence = true;
							 | 
						|||
| 
								 | 
							
										CollisionDrawCallCount++;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										if (CollisionDrawCallCount >= CollisionMaxDrawCallPerFrame)
							 | 
						|||
| 
								 | 
							
											break;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//处理CollisionMeshToRenameMoveUpdate 碰撞数据重命名&移动更新队列
							 | 
						|||
| 
								 | 
							
									for (int i = CollisionShareable->CollisionMeshToRenameMoveUpdate.Num() - 1; i >= 0; i--)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										FName& CollisionIDToUpdate = CollisionShareable->CollisionMeshToRenameMoveUpdate[i];
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										ensure(CollisionMesh.Find(CollisionIDToUpdate) != nullptr);
							 | 
						|||
| 
								 | 
							
										ensure(CollisionShareable->CollisionMeshData.Find(CollisionIDToUpdate) != nullptr);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										FCollisionMeshElement& El = *CollisionMesh.Find(CollisionIDToUpdate);
							 | 
						|||
| 
								 | 
							
										const FSWCollisionMeshElemData& El_Shareable = *CollisionShareable->CollisionMeshData.Find(CollisionIDToUpdate);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										El.Location = El_Shareable.Location;
							 | 
						|||
| 
								 | 
							
										El.MeshLocation = El_Shareable.MeshLocation;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										El.Mesh->SetLocationOnPhysicCookComplete(El.MeshLocation);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										UpdateCollisionMeshData(El);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										CollisionShareable->CollisionMeshToRenameMoveUpdate.RemoveAt(i);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										RequireRenderFence = true;
							 | 
						|||
| 
								 | 
							
										CollisionDrawCallCount++;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										if (CollisionDrawCallCount >= CollisionMaxDrawCallPerFrame)
							 | 
						|||
| 
								 | 
							
											break;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//开启CollisionProcess,需要等到执行完之后,才能执行CollisionPreprocessGPU()
							 | 
						|||
| 
								 | 
							
									if (RequireRenderFence)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										CollisionProcess.BeginFence();
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
										
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								FCollisionMeshElement& AShaderWorldActor::GetACollisionMesh(FName Name/*, FGuid AlreadyCreatedID*/)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									UWorld* World = GetWorld();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//存在可用CollisionMesh时,使用ID去寻找,如果找到则直接返回。并将AvailableCollisionMesh中的ID 转移到 UsedCollisionMesh
							 | 
						|||
| 
								 | 
							
									if (CollisionShareable.IsValid() && CollisionShareable->AvailableCollisionMesh.Num() > 0 )
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										if(FName* FoundName = CollisionShareable->AvailableCollisionMesh.Find(Name))
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											
							 | 
						|||
| 
								 | 
							
											if (FCollisionMeshElement* Elem = CollisionMesh.Find(Name))
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												UsedCollisionMesh.Add(Name);
							 | 
						|||
| 
								 | 
							
												CollisionShareable->UsedCollisionMesh.Add(Name);
							 | 
						|||
| 
								 | 
							
												CollisionShareable->AvailableCollisionMesh.Remove(Name);
							 | 
						|||
| 
								 | 
							
												Elem->SleepTime = -1.0;
							 | 
						|||
| 
								 | 
							
												return *Elem;
							 | 
						|||
| 
								 | 
							
											}			
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									FScopeLock CollisionMeshArrayAccess(CollisionMeshAccessLock.Get());
							 | 
						|||
| 
								 | 
							
									//往CollisionMesh Map添加新元素(FCollisionMeshElement)并设置其属性。
							 | 
						|||
| 
								 | 
							
									CollisionMesh.Add(Name, {});
							 | 
						|||
| 
								 | 
							
									FCollisionMeshElement& NewElem = *CollisionMesh.Find(Name);
							 | 
						|||
| 
								 | 
							
									NewElem.ID = Name;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									uint32 SizeT = (uint32)CollisionVerticesPerPatch;
							 | 
						|||
| 
								 | 
							
									NewElem.CollisionVerticesPerPatch = SizeT;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									NewElem.HeightData = MakeShared<FSWColorRead, ESPMode::ThreadSafe>();
							 | 
						|||
| 
								 | 
							
									NewElem.HeightData->ReadData.SetNum(CollisionVerticesPerPatch * CollisionVerticesPerPatch);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									NewElem.Mesh = NewObject<UShaderWorldCollisionComponent>(this, Name, RF_Transient | RF_TextExportTransient);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									NewElem.Mesh->SetUsedPhysicalMaterial(RootComp->PhysicalMaterials);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									NewElem.Mesh->bUseAsyncCooking = true;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									NewElem.Mesh->SetSWWorldVersion(Shareable_ID);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (RootComp)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										NewElem.Mesh->ComponentTags = RootComp->ComponentTags;
							 | 
						|||
| 
								 | 
							
										NewElem.Mesh->BodyInstance.CopyBodyInstancePropertiesFrom(&RootComp->BodyInstance);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										NewElem.Mesh->ComponentTags = RootComp->ComponentTags;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									else
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										UE_LOG(LogTemp, Warning, TEXT("UShaderWorldCollisionComponent Creation : invalid RootComp"))
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									NewElem.Mesh->SetCollisionObjectType(CollisionChannel);
							 | 
						|||
| 
								 | 
							
									NewElem.Mesh->SetGenerateOverlapEvents(true);
							 | 
						|||
| 
								 | 
							
									NewElem.Mesh->SetupAttachment(RootComponent);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//NewElem.Mesh->SetRelativeLocation(FVector(0.f, 0.f, 0.f));
							 | 
						|||
| 
								 | 
							
									NewElem.Mesh->bUseComplexAsSimpleCollision = true;
							 | 
						|||
| 
								 | 
							
									/*
							 | 
						|||
| 
								 | 
							
									NewElem.Mesh->SetUsingAbsoluteLocation(true);
							 | 
						|||
| 
								 | 
							
									NewElem.Mesh->SetUsingAbsoluteRotation(true);
							 | 
						|||
| 
								 | 
							
									*/
							 | 
						|||
| 
								 | 
							
									//NewElem.Mesh->bTraceComplexOnMove = false;
							 | 
						|||
| 
								 | 
							
									NewElem.MeshLocation = NewElem.Mesh->GetComponentLocation();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if WITH_EDITORONLY_DATA
							 | 
						|||
| 
								 | 
							
									NewElem.Mesh->bConsiderForActorPlacementWhenHidden = true;
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									NewElem.Mesh->RegisterComponent();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									TSharedPtr<FSWShareableVerticePositionBuffer, ESPMode::ThreadSafe> Vertices = MakeShared<FSWShareableVerticePositionBuffer, ESPMode::ThreadSafe>();
							 | 
						|||
| 
								 | 
							
									TSharedPtr<FSWShareableIndexBuffer, ESPMode::ThreadSafe> Triangles = MakeShared<FSWShareableIndexBuffer, ESPMode::ThreadSafe>();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									float Spacing = CollisionResolution;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if(CollisionBufferHolder.IsValid() && (!CollisionMesh.Find(CollisionBufferHolder) || (CollisionMesh.Find(CollisionBufferHolder) && !CollisionMesh.Find(CollisionBufferHolder)->Mesh)))
							 | 
						|||
| 
								 | 
							
										CollisionBufferHolder = "";
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//符合条件则重新创建碰撞GPU计算用RT。
							 | 
						|||
| 
								 | 
							
									if ( CollisionBufferHolder == "" || (CollisionBufferHolder != "" && CollisionBufferHolder == Name))
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										CollisionBufferHolder = Name;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										SW_RT(NewElem.CollisionRT, World, Name.ToString() + FString::FromInt(GetUniqueID()), SizeT, TF_Nearest, RTF_RGBA8)
							 | 
						|||
| 
								 | 
							
										RTAllocatedMemory(NewElem.CollisionRT)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										if (bExportPhysicalMaterialID_cached && LayerStoringMaterialID != "")
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											for (FSWProducers& layer : Producers)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												if (layer.LayerName == "Height" || layer.LayerName == "height")
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													continue;
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												if (layer.LayerName != "" && layer.MaterialToGenerateLayer)
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													NewElem.LayerOrder.Add(layer.LayerName);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													UShaderWorldRT2D* LayerRT = nullptr;
							 | 
						|||
| 
								 | 
							
													SW_RT(LayerRT, World, layer.LayerName + "_PhyMat_" + FString::FromInt(GetUniqueID()), SizeT, layer.LayerFiltering, layer.LayerFormat)
							 | 
						|||
| 
								 | 
							
														RTAllocatedMemory(LayerRT)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														NewElem.LayerComputeForPhysicalMaterial.Add(layer.LayerName, { LayerRT ,nullptr });
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												if (LayerStoringMaterialID == layer.LayerName)
							 | 
						|||
| 
								 | 
							
													break;
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										SW_RT(NewElem.CollisionRT_Duplicate, World, "RT_Temp_" + Name.ToString() + FString::FromInt(GetUniqueID()), SizeT, TF_Nearest, RTF_RGBA8)
							 | 
						|||
| 
								 | 
							
										RTAllocatedMemory(NewElem.CollisionRT_Duplicate)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										TArray<FVector2f> UV;
							 | 
						|||
| 
								 | 
							
										USWBlueprintFunctionLibrary::CreateGridMeshWelded(CollisionVerticesPerPatch, CollisionVerticesPerPatch, Triangles, Vertices, UV, Spacing);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											const int32 NumTriangles = Triangles->Indices.Num() / 3;
							 | 
						|||
| 
								 | 
							
											Triangles->Triangles_CollisionOnly.Empty();
							 | 
						|||
| 
								 | 
							
											Triangles->Triangles_CollisionOnly.Reserve(NumTriangles);
							 | 
						|||
| 
								 | 
							
											for (int32 TriIdx = 0; TriIdx < NumTriangles; TriIdx++)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												FTriIndices& Triangle = Triangles->Triangles_CollisionOnly.AddDefaulted_GetRef();
							 | 
						|||
| 
								 | 
							
												Triangle.v0 = Triangles->Indices[(TriIdx * 3) + 0] /* + VertexBase */;
							 | 
						|||
| 
								 | 
							
												Triangle.v1 = Triangles->Indices[(TriIdx * 3) + 1] /* + VertexBase */;
							 | 
						|||
| 
								 | 
							
												Triangle.v2 = Triangles->Indices[(TriIdx * 3) + 2] /* + VertexBase */;
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										/*
							 | 
						|||
| 
								 | 
							
										 * The data inside the Vertices shared pointer can and will change over time, while VerticesTemplate is immutable,
							 | 
						|||
| 
								 | 
							
										 * therefore we are making a persistent copy instead of using Vertices directly
							 | 
						|||
| 
								 | 
							
										 */
							 | 
						|||
| 
								 | 
							
										NewElem.Mesh->VerticesTemplate = MakeShared<FSWShareableVerticePositionBuffer, ESPMode::ThreadSafe>();
							 | 
						|||
| 
								 | 
							
										NewElem.Mesh->VerticesTemplate->Positions = Vertices->Positions;
							 | 
						|||
| 
								 | 
							
										NewElem.Mesh->VerticesTemplate->Positions3f = Vertices->Positions3f;
							 | 
						|||
| 
								 | 
							
										NewElem.Mesh->VerticesTemplate->MaterialIndices = Vertices->MaterialIndices;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										NewElem.Mesh->VerticesTemplate->PositionToTriangle = Vertices->PositionToTriangle;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										NewElem.Mesh->TrianglesTemplate = Triangles;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									else if(CollisionBufferHolder != "" && CollisionMesh.Find(CollisionBufferHolder) && !CollisionMesh.Find(CollisionBufferHolder)->Mesh->VerticesTemplate.IsValid())
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										/*
							 | 
						|||
| 
								 | 
							
										 * #TODO Should never occur, remove
							 | 
						|||
| 
								 | 
							
										 */
							 | 
						|||
| 
								 | 
							
								#if SWDEBUG
							 | 
						|||
| 
								 | 
							
										SW_LOG("Recreating Collision Vertice template")
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
										const FCollisionMeshElement& BufferHolder = *CollisionMesh.Find(CollisionBufferHolder);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										TArray<FVector2f> UV;
							 | 
						|||
| 
								 | 
							
										USWBlueprintFunctionLibrary::CreateGridMeshWelded(CollisionVerticesPerPatch, CollisionVerticesPerPatch, Triangles, Vertices, UV, Spacing);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											const int32 NumTriangles = Triangles->Indices.Num() / 3;
							 | 
						|||
| 
								 | 
							
											Triangles->Triangles_CollisionOnly.Empty();
							 | 
						|||
| 
								 | 
							
											Triangles->Triangles_CollisionOnly.Reserve(NumTriangles);
							 | 
						|||
| 
								 | 
							
											for (int32 TriIdx = 0; TriIdx < NumTriangles; TriIdx++)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												FTriIndices& Triangle = Triangles->Triangles_CollisionOnly.AddDefaulted_GetRef();
							 | 
						|||
| 
								 | 
							
												Triangle.v0 = Triangles->Indices[(TriIdx * 3) + 0] /* + VertexBase */;
							 | 
						|||
| 
								 | 
							
												Triangle.v1 = Triangles->Indices[(TriIdx * 3) + 1] /* + VertexBase */;
							 | 
						|||
| 
								 | 
							
												Triangle.v2 = Triangles->Indices[(TriIdx * 3) + 2] /* + VertexBase */;
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										BufferHolder.Mesh->VerticesTemplate = MakeShared<FSWShareableVerticePositionBuffer, ESPMode::ThreadSafe>();
							 | 
						|||
| 
								 | 
							
										BufferHolder.Mesh->VerticesTemplate->Positions = Vertices->Positions;
							 | 
						|||
| 
								 | 
							
										BufferHolder.Mesh->VerticesTemplate->Positions3f = Vertices->Positions3f;
							 | 
						|||
| 
								 | 
							
										BufferHolder.Mesh->VerticesTemplate->MaterialIndices = Vertices->MaterialIndices;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										BufferHolder.Mesh->VerticesTemplate->PositionToTriangle = Vertices->PositionToTriangle;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										BufferHolder.Mesh->TrianglesTemplate = Triangles;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										Vertices->Positions = BufferHolder.Mesh->VerticesTemplate->Positions;
							 | 
						|||
| 
								 | 
							
										Vertices->Positions3f = BufferHolder.Mesh->VerticesTemplate->Positions3f;
							 | 
						|||
| 
								 | 
							
										Vertices->MaterialIndices = BufferHolder.Mesh->VerticesTemplate->MaterialIndices;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										Triangles = BufferHolder.Mesh->TrianglesTemplate;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										SW_RT(NewElem.CollisionRT, World, Name.ToString() + FString::FromInt(GetUniqueID()), SizeT, TF_Nearest, RTF_RGBA8)
							 | 
						|||
| 
								 | 
							
										RTAllocatedMemory(NewElem.CollisionRT)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										if (bExportPhysicalMaterialID_cached && LayerStoringMaterialID != "")
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											for (FSWProducers& layer : Producers)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												if (layer.LayerName == "Height" || layer.LayerName == "height")
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													continue;
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												if (layer.LayerName != "" && layer.MaterialToGenerateLayer)
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													NewElem.LayerOrder.Add(layer.LayerName);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													UShaderWorldRT2D* LayerRT = nullptr;
							 | 
						|||
| 
								 | 
							
													SW_RT(LayerRT, World, layer.LayerName + "_PhyMat_" + FString::FromInt(GetUniqueID()), SizeT, layer.LayerFiltering, layer.LayerFormat)
							 | 
						|||
| 
								 | 
							
														RTAllocatedMemory(LayerRT)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														NewElem.LayerComputeForPhysicalMaterial.Add(layer.LayerName, { LayerRT ,nullptr });
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												if (LayerStoringMaterialID == layer.LayerName)
							 | 
						|||
| 
								 | 
							
													break;
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									else
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										check(CollisionMesh.Contains(CollisionBufferHolder))
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										const FCollisionMeshElement& BufferHolder = *CollisionMesh.Find(CollisionBufferHolder);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										check(BufferHolder.Mesh->VerticesTemplate.IsValid())
							 | 
						|||
| 
								 | 
							
										/*
							 | 
						|||
| 
								 | 
							
										 * No point copying irrelevant data that will be overriden once the computation is complete.
							 | 
						|||
| 
								 | 
							
										 */
							 | 
						|||
| 
								 | 
							
										Triangles = BufferHolder.Mesh->TrianglesTemplate;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										NewElem.CollisionRT = BufferHolder.CollisionRT;
							 | 
						|||
| 
								 | 
							
										NewElem.LayerOrder = BufferHolder.LayerOrder;
							 | 
						|||
| 
								 | 
							
										NewElem.LayerComputeForPhysicalMaterial = BufferHolder.LayerComputeForPhysicalMaterial;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									NewElem.Mesh->CreateMeshSection(0, Vertices, Triangles, false);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									/*
							 | 
						|||
| 
								 | 
							
									 * If not in editor mode, only make collision blue mesh visible if we asked for collisions to be visible
							 | 
						|||
| 
								 | 
							
									 * The renderthread will otherwise completely skip the collision meshes
							 | 
						|||
| 
								 | 
							
									 */
							 | 
						|||
| 
								 | 
							
									NewElem.Mesh->SetMeshSectionVisible(0, CollisionVisible);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (!CollisionMat)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
								#if SWDEBUG
							 | 
						|||
| 
								 | 
							
										SW_LOG("Material for Collision mesh not available for Shader World %s", *GetName())
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									else
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
								#if WITH_EDITOR
							 | 
						|||
| 
								 | 
							
										if ((CollisionBufferHolder != Name)
							 | 
						|||
| 
								 | 
							
											&& CollisionMesh.Contains(CollisionBufferHolder)
							 | 
						|||
| 
								 | 
							
											&& (*CollisionMesh.Find(CollisionBufferHolder)).Mesh)
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											NewElem.Mesh->SetMaterialFromOwner(0, (*CollisionMesh.Find(CollisionBufferHolder)).Mesh->GetMaterial(0));
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
										else
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											UMaterialInstanceDynamic* DynColMat = SWTakeCareOfMID(CollisionMat.Get(), this);
							 | 
						|||
| 
								 | 
							
											SWorldSubsystem->SetScalarParameterValue(DynColMat, "MakeCollisionVisible", 1.0);
							 | 
						|||
| 
								 | 
							
											SWorldSubsystem->SetScalarParameterValue(DynColMat, "CollisionResolution", CollisionResolution);
							 | 
						|||
| 
								 | 
							
											NewElem.Mesh->SetMaterialFromOwner(0, DynColMat);
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									UsedCollisionMesh.Add(Name);
							 | 
						|||
| 
								 | 
							
									CollisionShareable->UsedCollisionMesh.Add(Name);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//if (CollisionShareable->CollisionMeshData.Num() < CollisionMesh.Num())
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										if(!CollisionShareable->CollisionMeshData.Contains(Name))
							 | 
						|||
| 
								 | 
							
											CollisionShareable->CollisionMeshData.Add(Name, NewElem);
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									return *CollisionMesh.Find(Name);
							 | 
						|||
| 
								 | 
							
									//return CollisionMesh[CollisionMesh.Num() - 1];
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								void AShaderWorldActor::UpdateCollisionMeshData(FCollisionMeshElement& Mesh)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									FVector MesgLoc = FVector((Mesh.Location * CollisionResolution * (CollisionVerticesPerPatch - 1) + FIntVector(0.f, 0.f, 1) * HeightOnStart));
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (!Generator)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
								#if SWDEBUG
							 | 
						|||
| 
								 | 
							
										SW_LOG("Generator Material not available for Shader World %s", *GetName())
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									else
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										UWorld* World = GetWorld();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										//OPTION A : Compute collision form GPU readback
							 | 
						|||
| 
								 | 
							
										UMaterialInstanceDynamic* DynCollisionMat = Mesh.DynCollisionCompute;
							 | 
						|||
| 
								 | 
							
										//如果生成高度材质无效,这里将会进行初始化。
							 | 
						|||
| 
								 | 
							
										if (!DynCollisionMat)
							 | 
						|||
| 
								 | 
							
										{	
							 | 
						|||
| 
								 | 
							
											DynCollisionMat = SWTakeCareOfMID(Generator.Get(), this);
							 | 
						|||
| 
								 | 
							
											Mesh.DynCollisionCompute = DynCollisionMat;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											SWorldSubsystem->SetScalarParameterValue(DynCollisionMat, "NoMargin", 1.f);
							 | 
						|||
| 
								 | 
							
											SWorldSubsystem->SetScalarParameterValue(DynCollisionMat, "TexelPerSide", CollisionVerticesPerPatch);
							 | 
						|||
| 
								 | 
							
											SWorldSubsystem->SetScalarParameterValue(DynCollisionMat, "PatchFullSize", CollisionResolution * (CollisionVerticesPerPatch - 1));
							 | 
						|||
| 
								 | 
							
											SWorldSubsystem->SetScalarParameterValue(DynCollisionMat, "MeshScale", CollisionResolution * (CollisionVerticesPerPatch <= 1 ? 1 : CollisionVerticesPerPatch));
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											SWorldSubsystem->SetScalarParameterValue(DynCollisionMat, "N", CollisionVerticesPerPatch);
							 | 
						|||
| 
								 | 
							
											SWorldSubsystem->SetScalarParameterValue(DynCollisionMat, "CacheRes", CollisionVerticesPerPatch);
							 | 
						|||
| 
								 | 
							
											SWorldSubsystem->SetScalarParameterValue(DynCollisionMat, "LocalGridScaling", CollisionResolution);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											if (bExportPhysicalMaterialID_cached && LayerStoringMaterialID != "")
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												for (FSWProducers& Layer : Producers)
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													if (Layer.LayerName == "Height" || Layer.LayerName == "height")
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														continue;
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													if (Layer.LayerName != "" && Layer.MaterialToGenerateLayer)
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														check(Mesh.LayerComputeForPhysicalMaterial.Contains(Layer.LayerName))						
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														UMaterialInstanceDynamic* LayerPartitionDynMat = SWTakeCareOfMID(Layer.MaterialToGenerateLayer, this);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														FSWCollisionLayerData& CLayerData = *Mesh.LayerComputeForPhysicalMaterial.Find(Layer.LayerName);
							 | 
						|||
| 
								 | 
							
														CLayerData.DynMat = LayerPartitionDynMat;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														SWorldSubsystem->SetScalarParameterValue(LayerPartitionDynMat, "PatchFullSize", CollisionResolution* (CollisionVerticesPerPatch - 1));
							 | 
						|||
| 
								 | 
							
														SWorldSubsystem->SetScalarParameterValue(LayerPartitionDynMat, "TexelPerSide", CollisionVerticesPerPatch);
							 | 
						|||
| 
								 | 
							
														SWorldSubsystem->SetScalarParameterValue(LayerPartitionDynMat, "NoMargin", 1.f);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														SWorldSubsystem->SetScalarParameterValue(LayerPartitionDynMat, "MeshScale", CollisionResolution * (CollisionVerticesPerPatch <= 1 ? 1 : CollisionVerticesPerPatch));
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													
							 | 
						|||
| 
								 | 
							
														SWorldSubsystem->SetScalarParameterValue(LayerPartitionDynMat, "N", CollisionVerticesPerPatch);
							 | 
						|||
| 
								 | 
							
														SWorldSubsystem->SetScalarParameterValue(LayerPartitionDynMat, "CacheRes", CollisionVerticesPerPatch);
							 | 
						|||
| 
								 | 
							
														SWorldSubsystem->SetScalarParameterValue(LayerPartitionDynMat, "LocalGridScaling", CollisionResolution);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														SWorldSubsystem->SetScalarParameterValue(LayerPartitionDynMat, "NormalMapSelect", 1.f);						
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													if (LayerStoringMaterialID == Layer.LayerName)
							 | 
						|||
| 
								 | 
							
														break;
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											if (bUseMaterialCollection)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												if (UShaderWorld_Material_Collection* MC = GetValid(MaterialCollection))
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													for (auto& IDMat : MC->MaterialNameToID)
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														SWorldSubsystem->SetScalarParameterValue(DynCollisionMat, FName(IDMat.Key), IDMat.Value);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														for (auto& CollisionLayerC : Mesh.LayerComputeForPhysicalMaterial)
							 | 
						|||
| 
								 | 
							
														{
							 | 
						|||
| 
								 | 
							
															if (CollisionLayerC.Value.DynMat)
							 | 
						|||
| 
								 | 
							
																SWorldSubsystem->SetScalarParameterValue(CollisionLayerC.Value.DynMat, FName(IDMat.Key), IDMat.Value);
							 | 
						|||
| 
								 | 
							
														}
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
											else
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												for (auto& IDMat : MaterialNameToID)
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													SWorldSubsystem->SetScalarParameterValue(DynCollisionMat, FName(IDMat.Key), IDMat.Value);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													for (auto& CollisionLayerC : Mesh.LayerComputeForPhysicalMaterial)
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														if (CollisionLayerC.Value.DynMat)
							 | 
						|||
| 
								 | 
							
															SWorldSubsystem->SetScalarParameterValue(CollisionLayerC.Value.DynMat, FName(IDMat.Key), IDMat.Value);
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											TSet<FName> UsedNames;
							 | 
						|||
| 
								 | 
							
											for (FInstancedStruct& Seed : CurrentSeedsArray.SeedsArray)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												if (Seed.IsValid())
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													const UScriptStruct* Type = Seed.GetScriptStruct();
							 | 
						|||
| 
								 | 
							
													CA_ASSUME(Type);
							 | 
						|||
| 
								 | 
							
													if (Type->IsChildOf(FTextureSeed::StaticStruct()))
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														FTextureSeed& TypedSeed = Seed.GetMutable<FTextureSeed>();
							 | 
						|||
| 
								 | 
							
														if (!UsedNames.Contains(TypedSeed.SeedName))
							 | 
						|||
| 
								 | 
							
														{
							 | 
						|||
| 
								 | 
							
															UsedNames.Add(TypedSeed.SeedName);
							 | 
						|||
| 
								 | 
							
															SWorldSubsystem->SetTextureParameterValue(Mesh.DynCollisionCompute, TypedSeed.SeedName, TypedSeed.Value);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
															for (auto& LayerEl : Mesh.LayerComputeForPhysicalMaterial)
							 | 
						|||
| 
								 | 
							
															{
							 | 
						|||
| 
								 | 
							
																SWorldSubsystem->SetTextureParameterValue(LayerEl.Value.DynMat, TypedSeed.SeedName, TypedSeed.Value);
							 | 
						|||
| 
								 | 
							
															}
							 | 
						|||
| 
								 | 
							
														}
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
													else if (Type->IsChildOf(FLinearColorSeed::StaticStruct()))
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														FLinearColorSeed& TypedSeed = Seed.GetMutable<FLinearColorSeed>();
							 | 
						|||
| 
								 | 
							
														if (!UsedNames.Contains(TypedSeed.SeedName))
							 | 
						|||
| 
								 | 
							
														{
							 | 
						|||
| 
								 | 
							
															UsedNames.Add(TypedSeed.SeedName);
							 | 
						|||
| 
								 | 
							
															SWorldSubsystem->SetVectorParameterValue(Mesh.DynCollisionCompute, TypedSeed.SeedName, TypedSeed.Value);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
															for (auto& LayerEl : Mesh.LayerComputeForPhysicalMaterial)
							 | 
						|||
| 
								 | 
							
															{
							 | 
						|||
| 
								 | 
							
																SWorldSubsystem->SetVectorParameterValue(LayerEl.Value.DynMat, TypedSeed.SeedName, TypedSeed.Value);
							 | 
						|||
| 
								 | 
							
															}
							 | 
						|||
| 
								 | 
							
														}
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
													else if (Type->IsChildOf(FScalarSeed::StaticStruct()))
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														FScalarSeed& TypedSeed = Seed.GetMutable<FScalarSeed>();
							 | 
						|||
| 
								 | 
							
														if (!UsedNames.Contains(TypedSeed.SeedName))
							 | 
						|||
| 
								 | 
							
														{
							 | 
						|||
| 
								 | 
							
															UsedNames.Add(TypedSeed.SeedName);
							 | 
						|||
| 
								 | 
							
															SWorldSubsystem->SetScalarParameterValue(Mesh.DynCollisionCompute, TypedSeed.SeedName, TypedSeed.Value);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
															for (auto& LayerEl : Mesh.LayerComputeForPhysicalMaterial)
							 | 
						|||
| 
								 | 
							
															{
							 | 
						|||
| 
								 | 
							
																SWorldSubsystem->SetScalarParameterValue(LayerEl.Value.DynMat, TypedSeed.SeedName, TypedSeed.Value);
							 | 
						|||
| 
								 | 
							
															}
							 | 
						|||
| 
								 | 
							
														}
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
													else
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
								#if SWDEBUG
							 | 
						|||
| 
								 | 
							
														SW_LOG("Invalid Seed type found: '%s'", *GetPathNameSafe(Type));
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										SWorldSubsystem->SetVectorParameterValue(DynCollisionMat,"PatchLocation", MesgLoc);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										//UKismetRenderingLibrary::ClearRenderTarget2D(this, Mesh.CollisionRT, FLinearColor::Black);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if SW_COMPUTE_GENERATION
							 | 
						|||
| 
								 | 
							
										//使用CS计算碰撞数据,最后写入FCollisionMeshElement.CollisionRT
							 | 
						|||
| 
								 | 
							
										SWorldSubsystem->DrawMaterialToRenderTarget(
							 | 
						|||
| 
								 | 
							
											{ false,
							 | 
						|||
| 
								 | 
							
												 false,
							 | 
						|||
| 
								 | 
							
												GetWorld()->Scene,
							 | 
						|||
| 
								 | 
							
												(float)GetWorld()->TimeSeconds,
							 | 
						|||
| 
								 | 
							
												false,
							 | 
						|||
| 
								 | 
							
												true,
							 | 
						|||
| 
								 | 
							
												Mesh.CollisionRT->SizeX,
							 | 
						|||
| 
								 | 
							
												(int32)(CollisionVerticesPerPatch - 1) * CollisionResolution,
							 | 
						|||
| 
								 | 
							
												FVector(MesgLoc),
							 | 
						|||
| 
								 | 
							
												FIntPoint(0),
							 | 
						|||
| 
								 | 
							
												FIntPoint(Mesh.CollisionVerticesPerPatch,Mesh.CollisionVerticesPerPatch),
							 | 
						|||
| 
								 | 
							
												false,
							 | 
						|||
| 
								 | 
							
												ReadRequestLocation,
							 | 
						|||
| 
								 | 
							
												DynCollisionMat,
							 | 
						|||
| 
								 | 
							
												 Mesh.CollisionRT
							 | 
						|||
| 
								 | 
							
											});
							 | 
						|||
| 
								 | 
							
								#else
							 | 
						|||
| 
								 | 
							
										UKismetRenderingLibrary::DrawMaterialToRenderTarget(this, Mesh.CollisionRT, DynCollisionMat);
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										if (IsValid(BrushManager))
							 | 
						|||
| 
								 | 
							
											BrushManager->ApplyBrushStackToHeightMap(this, 0, Mesh.CollisionRT, Mesh.CollisionVerticesPerPatch, MesgLoc, CollisionResolution, CollisionVerticesPerPatch, true /*Collision heightmap have no border*/);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										//输出物理材质ID缓存,bExportPhysicalMaterialID_cached默认为false。
							 | 
						|||
| 
								 | 
							
										if (bExportPhysicalMaterialID_cached && (LayerStoringMaterialID != ""))
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												int32 DrawCallCount = 0;
							 | 
						|||
| 
								 | 
							
												TArray<UShaderWorldRT2D*> PreviousLayer;
							 | 
						|||
| 
								 | 
							
												PreviousLayer.Reserve(Mesh.LayerOrder.Num());
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												int32 LayerIndice = 0;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												for (int k = 0; k < Mesh.LayerOrder.Num(); k++)
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													FString LayerName = Mesh.LayerOrder[k];
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													check(Mesh.LayerComputeForPhysicalMaterial.Contains(LayerName))
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													FSWCollisionLayerData& CLayerData = *Mesh.LayerComputeForPhysicalMaterial.Find(LayerName);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													if (!CLayerData.DynMat)
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														UE_LOG(LogTemp, Warning, TEXT("ERROR drawing layers for Physical material: !CLayerData.DynMat[%d]"), k);
							 | 
						|||
| 
								 | 
							
														continue;
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													if (UShaderWorldRT2D* Layer_RT_To_Produce = CLayerData.RT)
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														SWorldSubsystem->SetVectorParameterValue(CLayerData.DynMat, "PatchLocation", MesgLoc);
							 | 
						|||
| 
								 | 
							
														SWorldSubsystem->SetTextureParameterValue(CLayerData.DynMat, "HeightMap", Mesh.CollisionRT);
							 | 
						|||
| 
								 | 
							
														SWorldSubsystem->SetTextureParameterValue(CLayerData.DynMat, "NormalMap", Mesh.CollisionRT);//#TODO Support normal map for collision ?
							 | 
						|||
| 
								 | 
							
														for (int u = 0; u < LayerIndice; u++)
							 | 
						|||
| 
								 | 
							
														{
							 | 
						|||
| 
								 | 
							
															SWorldSubsystem->SetTextureParameterValue(CLayerData.DynMat, FName(*Mesh.LayerOrder[u]), PreviousLayer[u]);
							 | 
						|||
| 
								 | 
							
														}
							 | 
						|||
| 
								 | 
							
								#if SW_COMPUTE_GENERATION
							 | 
						|||
| 
								 | 
							
														SWorldSubsystem->DrawMaterialToRenderTarget(
							 | 
						|||
| 
								 | 
							
															{ false,
							 | 
						|||
| 
								 | 
							
																 false,
							 | 
						|||
| 
								 | 
							
																GetWorld()->Scene,
							 | 
						|||
| 
								 | 
							
																(float)GetWorld()->TimeSeconds,
							 | 
						|||
| 
								 | 
							
																false,
							 | 
						|||
| 
								 | 
							
																true,
							 | 
						|||
| 
								 | 
							
																Layer_RT_To_Produce->SizeX,
							 | 
						|||
| 
								 | 
							
																(int32)(CollisionVerticesPerPatch - 1) * CollisionResolution,
							 | 
						|||
| 
								 | 
							
																MesgLoc,
							 | 
						|||
| 
								 | 
							
																FIntPoint(0),
							 | 
						|||
| 
								 | 
							
												FIntPoint(Mesh.CollisionVerticesPerPatch,Mesh.CollisionVerticesPerPatch),
							 | 
						|||
| 
								 | 
							
																false,
							 | 
						|||
| 
								 | 
							
																ReadRequestLocation,
							 | 
						|||
| 
								 | 
							
																 CLayerData.DynMat,
							 | 
						|||
| 
								 | 
							
																Layer_RT_To_Produce,
							 | 
						|||
| 
								 | 
							
																Mesh.CollisionRT,
							 | 
						|||
| 
								 | 
							
																Mesh.CollisionRT//#TODO Support normal map for collision ?
							 | 
						|||
| 
								 | 
							
															});
							 | 
						|||
| 
								 | 
							
								#else
							 | 
						|||
| 
								 | 
							
														UKismetRenderingLibrary::DrawMaterialToRenderTarget(this, Layer_RT_To_Produce, Elem.LayerPartitionMatDyn[k]);
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
														DrawCallCount++;
							 | 
						|||
| 
								 | 
							
														
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														if (IsValid(BrushManager))
							 | 
						|||
| 
								 | 
							
															DrawCallCount += BrushManager->ApplyBrushStackToLayer(this, 0, Layer_RT_To_Produce, Mesh.CollisionVerticesPerPatch, MesgLoc, CollisionResolution, CollisionVerticesPerPatch, LayerName);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														PreviousLayer.Add(Layer_RT_To_Produce);
							 | 
						|||
| 
								 | 
							
														LayerIndice++;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														if (LayerStoringMaterialID == LayerName)
							 | 
						|||
| 
								 | 
							
														{
							 | 
						|||
| 
								 | 
							
															float PatchSize = (CollisionVerticesPerPatch - 1) * CollisionResolution;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
															SWorldSubsystem->CopyAtoB(Mesh.CollisionRT, (*CollisionMesh.Find(CollisionBufferHolder)).CollisionRT_Duplicate);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
															uint8 channel = (static_cast<uint8>(LayerChannelStoringID)) + 1;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
															SWorldSubsystem->CopyAtoB(Layer_RT_To_Produce, Mesh.CollisionRT, (*CollisionMesh.Find(CollisionBufferHolder)).CollisionRT_Duplicate, 0, channel, FVector2D(MesgLoc), FVector2D(MesgLoc), PatchSize, PatchSize, SWCopyConfig::AlphaChannelCombine);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
															break;
							 | 
						|||
| 
								 | 
							
														}
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										if (false && bExportPhysicalMaterialID_cached && (LayerStoringMaterialID != "") && GetMeshNum() > 0 && CollisionMesh.Num() > 0 && (*CollisionMesh.Find(CollisionBufferHolder)).CollisionRT_Duplicate)
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											if (USWorldSubsystem* ShaderWorldSubsystem = SWorldSubsystem)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												bool LayerIsRelevant = false;
							 | 
						|||
| 
								 | 
							
												FString LayerSource = LayerStoringMaterialID.ToString();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												for (auto& La : Producers)
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													if (La.LayerName == "Height" || La.LayerName == "height")
							 | 
						|||
| 
								 | 
							
														continue;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													if (La.LayerName == LayerSource)
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														LayerIsRelevant = true;
							 | 
						|||
| 
								 | 
							
														break;
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												if (LayerIsRelevant)
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													FVector2D Location_Mesh(MesgLoc);
							 | 
						|||
| 
								 | 
							
													FVector2D Extent = CollisionResolution * (CollisionVerticesPerPatch - 1) / 2.f * FVector2D(1.f, 1.f);//Margin
							 | 
						|||
| 
								 | 
							
													FBox2D LocalMeshBox(Location_Mesh - Extent, Location_Mesh + Extent);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													int LOD_Candidate = -1;
							 | 
						|||
| 
								 | 
							
													///////////////////////////////
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													for (int k = 0; k < GetMeshNum(); k++)
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														FClipMapMeshElement& Elem_Local = GetMesh(k);
							 | 
						|||
| 
								 | 
							
														FIntVector ClipMapLocation = Elem_Local.Location - GetWorld()->OriginLocation;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														FVector2D Location_Elem_Local(ClipMapLocation.X, ClipMapLocation.Y);
							 | 
						|||
| 
								 | 
							
														FVector2D Extent_Elem_Local = Elem_Local.GridSpacing * ((Elem_Local.N - 1) / 2) * FVector2D(1.f, 1.f);
							 | 
						|||
| 
								 | 
							
														FBox2D Elem_Local_Footprint(Location_Elem_Local - Extent_Elem_Local, Location_Elem_Local + Extent_Elem_Local);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														if (Elem_Local_Footprint.IsInside(LocalMeshBox) && (Elem_Local.IsSectionVisible(0) || Elem_Local.IsSectionVisible(1)))
							 | 
						|||
| 
								 | 
							
														{
							 | 
						|||
| 
								 | 
							
															LOD_Candidate = k;
							 | 
						|||
| 
								 | 
							
														}
							 | 
						|||
| 
								 | 
							
														else
							 | 
						|||
| 
								 | 
							
														{
							 | 
						|||
| 
								 | 
							
															break;
							 | 
						|||
| 
								 | 
							
														}
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													if (LOD_Candidate >= 0)
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														FClipMapMeshElement& Elem_Local = GetMesh(LOD_Candidate);
							 | 
						|||
| 
								 | 
							
														float PatchSize = (Elem_Local.N - 1) * Elem_Local.GridSpacing;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														for (int k = 0; k < Elem_Local.LandLayers.Num(); k++)
							 | 
						|||
| 
								 | 
							
														{
							 | 
						|||
| 
								 | 
							
															if (Elem_Local.LandLayers_names[k] == LayerStoringMaterialID)
							 | 
						|||
| 
								 | 
							
															{
							 | 
						|||
| 
								 | 
							
																ShaderWorldSubsystem->CopyAtoB(Mesh.CollisionRT, (*CollisionMesh.Find(CollisionBufferHolder)).CollisionRT_Duplicate);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
																uint8 channel = (static_cast<uint8>(LayerChannelStoringID)) + 1;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
																ShaderWorldSubsystem->CopyAtoB(Elem_Local.LandLayers[k], Mesh.CollisionRT, (*CollisionMesh.Find(CollisionBufferHolder)).CollisionRT_Duplicate, 0, channel, FVector2D(FVector(Elem_Local.Location)), FVector2D(MesgLoc), PatchSize, CollisionResolution * (CollisionVerticesPerPatch - 1), SWCopyConfig::AlphaChannelCombine);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
																break;
							 | 
						|||
| 
								 | 
							
															}
							 | 
						|||
| 
								 | 
							
														}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
													else
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														//UE_LOG(LogTemp, Warning, TEXT("Non Admissible LOD_Candidate %d"), LOD_Candidate);
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
												else
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													UE_LOG(LogTemp, Warning, TEXT("No relevant data layer"));
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										if (!Mesh.HeightData.IsValid())
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											Mesh.HeightData = MakeShared<FSWColorRead, ESPMode::ThreadSafe>();
							 | 
						|||
| 
								 | 
							
											Mesh.HeightData->ReadData.SetNum(CollisionVerticesPerPatch * CollisionVerticesPerPatch);
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										if (!Mesh.ReadBackCompletion.IsValid())
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											Mesh.ReadBackCompletion = MakeShared<FThreadSafeBool, ESPMode::ThreadSafe>();
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										//设置 碰撞GPU数据回读完成 变量为false
							 | 
						|||
| 
								 | 
							
										Mesh.ReadBackCompletion->AtomicSet(false);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										//ShaderWorld::ReadPixelsFromRT(Mesh.CollisionRT, Mesh);
							 | 
						|||
| 
								 | 
							
										//ShaderWorld::AsyncReadPixelsFromRT(Mesh.CollisionRT, Mesh.HeightData, Mesh.ReadBackCompletion);
							 | 
						|||
| 
								 | 
							
										//从FCollisionMeshElement.CollisionRT读取数据并且写入FCollisionMeshElement.HeightData。
							 | 
						|||
| 
								 | 
							
										SWorldSubsystem->AsyncReadPixelsFromRT(Mesh.CollisionRT, Mesh.HeightData, Mesh.ReadBackCompletion);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										//将ID添加到CollisionReadToProcess 碰撞数据回读队列,
							 | 
						|||
| 
								 | 
							
										CollisionReadToProcess.Add(Mesh.ID);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										return;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									return;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								#### CollisionCPU
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void AShaderWorldActor::CollisionCPU()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									SCOPED_NAMED_EVENT_TEXT("AShaderWorldActor::CollisionCPU()", FColor::Magenta);
							 | 
						|||
| 
								 | 
							
									SW_FCT_CYCLE()
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										if ((*bPreprocessingCollisionUpdate.Get()) ||
							 | 
						|||
| 
								 | 
							
											CollisionShareable->CollisionMeshToUpdate.Num() > 0 ||
							 | 
						|||
| 
								 | 
							
											CollisionShareable->CollisionMeshToRenameMoveUpdate.Num() > 0 ||
							 | 
						|||
| 
								 | 
							
											CollisionShareable->CollisionMeshToCreate.Num() > 0)
							 | 
						|||
| 
								 | 
							
											return;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									UWorld* World = GetWorld();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//SW Brush相关
							 | 
						|||
| 
								 | 
							
									bool bBrushManagerAskedRedraw = BrushManager && (BrushManagerRedrawScopes_collision.Num() > 0);
							 | 
						|||
| 
								 | 
							
									FVector LocalActorLocation = GetActorLocation();
							 | 
						|||
| 
								 | 
							
									FIntVector LocalOriginLocation = GetWorld()->OriginLocation;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									TArray<FBox2D> BrushRedrawScope;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (bBrushManagerAskedRedraw)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										BrushRedrawScope = MoveTemp(BrushManagerRedrawScopes_collision);
							 | 
						|||
| 
								 | 
							
										BrushManagerRedrawScopes_collision.Empty();
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//通过AShaderWorldActor::UpdateCollisionInRegion()来添加碰撞重建区域
							 | 
						|||
| 
								 | 
							
									bool bExternalCollisionRebuildRequest = !CollisionUpdateRequest.IsEmpty();
							 | 
						|||
| 
								 | 
							
									FBox2D BPCollisionRebuildRequest(ForceInit);
							 | 
						|||
| 
								 | 
							
									//从CollisionUpdateRequest队列中取出碰撞更新范围
							 | 
						|||
| 
								 | 
							
									if (bExternalCollisionRebuildRequest)
							 | 
						|||
| 
								 | 
							
										CollisionUpdateRequest.Dequeue(BPCollisionRebuildRequest);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									TArray<ShaderWorld::FVisitor> VisitorLocations;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Use latest camera we know if current array is empty
							 | 
						|||
| 
								 | 
							
									//在BeginPlay()会将ShaderWorld Actor的Location添加到CameraLocations中。
							 | 
						|||
| 
								 | 
							
									//在UpdateCameraLocation()中会将,这个函数会在Setup()中调用。
							 | 
						|||
| 
								 | 
							
									// USWorldSubsystem::Tick()中会调用UpdateVisitors()获取所有USW_CollisionComponent。
							 | 
						|||
| 
								 | 
							
									if (CameraLocations.Num() <= 0)
							 | 
						|||
| 
								 | 
							
										VisitorLocations.Add(CamLocation);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									VisitorLocations.Append(CameraLocations);
							 | 
						|||
| 
								 | 
							
									//将bPreprocessingCollisionUpdate线程安全变量设置为true
							 | 
						|||
| 
								 | 
							
									(*bPreprocessingCollisionUpdate.Get()) = true;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									Async(EAsyncExecution::TaskGraph, [Completion = bPreprocessingCollisionUpdate, CollData = CollisionShareable,
							 | 
						|||
| 
								 | 
							
										VisitorLocations, bBrushManagerAskedRedraw, BrushScope = MoveTemp(BrushRedrawScope), bExternalCollisionRebuildRequest,
							 | 
						|||
| 
								 | 
							
										BPRecomputeScope = BPCollisionRebuildRequest, ColRingCount = CollisionGridMaxRingNumber, LocalActorLocation, LocalOriginLocation,
							 | 
						|||
| 
								 | 
							
										Height0 = HeightOnStart,  Bounded = WorldHasBounds_OnRebuild, GBounds = WorldBoundsOnRebuild, Lock = CollisionMeshAccessLock]
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											//CollisionShareable无效则返回
							 | 
						|||
| 
								 | 
							
											if (!CollData.IsValid())
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												if (Completion.IsValid())
							 | 
						|||
| 
								 | 
							
													(*Completion.Get()) = false;
							 | 
						|||
| 
								 | 
							
												return;
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											FScopeLock CollisionMeshArrayAccess(Lock.Get());
							 | 
						|||
| 
								 | 
							
											//Brush相关
							 | 
						|||
| 
								 | 
							
											double CollisionWidth = CollData->CollisionResolution * (CollData->VerticePerPatch - 1);
							 | 
						|||
| 
								 | 
							
											TMap<FIntVector, FVector> BrushRedraws;
							 | 
						|||
| 
								 | 
							
											for (const FBox2d& B : BrushScope)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												const int32 MinBoxX_local = FMath::FloorToInt(((double)(B.Min.X + LocalOriginLocation.X)) / CollisionWidth + 0.45);
							 | 
						|||
| 
								 | 
							
												const int32 MinBoxY_local = FMath::FloorToInt(((double)(B.Min.Y + LocalOriginLocation.Y)) / CollisionWidth + 0.45);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												const int32 MaxBoxX_local = FMath::FloorToInt(((double)(B.Max.X + LocalOriginLocation.X)) / CollisionWidth + 0.55);
							 | 
						|||
| 
								 | 
							
												const int32 MaxBoxY_local = FMath::FloorToInt(((double)(B.Max.Y + LocalOriginLocation.Y)) / CollisionWidth + 0.55);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												for (int32 X_iter = MinBoxX_local; X_iter <= MaxBoxX_local; X_iter++)
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													for (int32 Y_iter = MinBoxY_local; Y_iter <= MaxBoxY_local; Y_iter++)
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														BrushRedraws.Add(FIntVector(X_iter, Y_iter, 0));
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											/*
							 | 
						|||
| 
								 | 
							
											 * Get World Bounds in centimeters
							 | 
						|||
| 
								 | 
							
											 */
							 | 
						|||
| 
								 | 
							
											FBox SWorldBounds = GBounds;
							 | 
						|||
| 
								 | 
							
											SWorldBounds.Min *= 100.0;
							 | 
						|||
| 
								 | 
							
											SWorldBounds.Max *= 100.0;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											TSet<FIntVector> ExternalCollisionsBounds;
							 | 
						|||
| 
								 | 
							
											for (const ShaderWorld::FVisitor& SingleCamLoc : VisitorLocations)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												if (SingleCamLoc.Bounds.IsValid)
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													ExternalCollisionsBounds.Append(USWBlueprintFunctionLibrary::GetCollisionMeshesLayout(CollisionWidth, SingleCamLoc.Bounds, SWorldBounds));
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											CollData->MultipleCamera.Empty();
							 | 
						|||
| 
								 | 
							
											CollData->LocRefs.Empty();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											//遍历所有Visitor,之后往CollisionShareable中的LocRefs、MultipleCamera添加计算结果。
							 | 
						|||
| 
								 | 
							
											for (const ShaderWorld::FVisitor& SingleCamLoc : VisitorLocations)
							 | 
						|||
| 
								 | 
							
											{			
							 | 
						|||
| 
								 | 
							
												if (SingleCamLoc.Bounds.IsValid)
							 | 
						|||
| 
								 | 
							
													continue;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												double Cam_X_local = SingleCamLoc.Location.X + LocalOriginLocation.X;
							 | 
						|||
| 
								 | 
							
												double Cam_Y_local = SingleCamLoc.Location.Y + LocalOriginLocation.Y;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												if (Bounded)
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													Cam_X_local = FMath::Max(FMath::Min(Cam_X_local, GBounds.Max.X * 100.0), GBounds.Min.X * 100.0);
							 | 
						|||
| 
								 | 
							
													Cam_Y_local = FMath::Max(FMath::Min(Cam_Y_local, GBounds.Max.Y * 100.0), GBounds.Min.Y * 100.0);					
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												const int CamX_local = FMath::RoundToInt(Cam_X_local / CollisionWidth);
							 | 
						|||
| 
								 | 
							
												const int CamY_local = FMath::RoundToInt(Cam_Y_local / CollisionWidth);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												FIntVector LocRef_local = FIntVector(CamX_local, CamY_local, 0.f) * CollisionWidth + FIntVector(0.f, 0.f, 1) * Height0 - LocalOriginLocation;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												int32 LocalRingCount = FMath::Clamp(FMath::Floor(FMath::Abs(SingleCamLoc.Range * 100.0) / CollisionWidth), 1, ColRingCount);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												CollData->LocRefs.Add(LocRef_local, LocalRingCount);
							 | 
						|||
| 
								 | 
							
												CollData->MultipleCamera.Add(FIntVector(CamX_local, CamY_local, 0), LocalRingCount);
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											TArray<FName> NameToRemove;
							 | 
						|||
| 
								 | 
							
											for (const FName& CollID : CollData->UsedCollisionMesh)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												FSWCollisionMeshElemData& El = *CollData->CollisionMeshData.Find(CollID);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												bool BeyondCriteria_local = !ExternalCollisionsBounds.Contains(El.Location);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												for (auto& Elem : CollData->LocRefs)
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													FIntVector& SingleLocRef = Elem.Key;
							 | 
						|||
| 
								 | 
							
													int32& LocalRingCount = Elem.Value;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													const FVector ToCompLocal = FVector(FIntVector(El.MeshLocation) - SingleLocRef) / CollisionWidth;
							 | 
						|||
| 
								 | 
							
													BeyondCriteria_local = BeyondCriteria_local && (FMath::Abs(ToCompLocal.X) > LocalRingCount + .1f || FMath::Abs(ToCompLocal.Y) > LocalRingCount + .1f);
							 | 
						|||
| 
								 | 
							
													if (!BeyondCriteria_local)
							 | 
						|||
| 
								 | 
							
														break;
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												if (BeyondCriteria_local)
							 | 
						|||
| 
								 | 
							
												{					
							 | 
						|||
| 
								 | 
							
													CollData->AvailableCollisionMesh.Add(CollID);
							 | 
						|||
| 
								 | 
							
													NameToRemove.Add(CollID);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													for (auto It = CollData->GroundCollisionLayout.CreateConstIterator(); It; ++It)
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														if(It->Value == CollID)
							 | 
						|||
| 
								 | 
							
														{
							 | 
						|||
| 
								 | 
							
															CollData->GroundCollisionLayout.Remove(It->Key);
							 | 
						|||
| 
								 | 
							
															break;
							 | 
						|||
| 
								 | 
							
														}
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
												else
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													if (bBrushManagerAskedRedraw || bExternalCollisionRebuildRequest)
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														bool UpdateRequested = false;
							 | 
						|||
| 
								 | 
							
														if (bBrushManagerAskedRedraw)
							 | 
						|||
| 
								 | 
							
														{
							 | 
						|||
| 
								 | 
							
															if (BrushRedraws.Contains(El.Location))
							 | 
						|||
| 
								 | 
							
															{
							 | 
						|||
| 
								 | 
							
																CollData->CollisionMeshToUpdate.Add(CollID);
							 | 
						|||
| 
								 | 
							
																UpdateRequested = true;
							 | 
						|||
| 
								 | 
							
															}
							 | 
						|||
| 
								 | 
							
														}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														if (!UpdateRequested && bExternalCollisionRebuildRequest)
							 | 
						|||
| 
								 | 
							
														{
							 | 
						|||
| 
								 | 
							
															const FVector Location_LocalOrigin = FVector(El.Location * CollisionWidth + FIntVector(0, 0, 1) * LocalActorLocation.Z - LocalOriginLocation);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
															FVector2D Location_Mesh(Location_LocalOrigin.X, Location_LocalOrigin.Y);
							 | 
						|||
| 
								 | 
							
															FVector2D Extent = CollisionWidth / 2.f * FVector2D(1.f, 1.f);
							 | 
						|||
| 
								 | 
							
															FBox2D LocalCollisionMeshBox(Location_Mesh - Extent, Location_Mesh + Extent);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
															if (BPRecomputeScope.Intersect(LocalCollisionMeshBox))
							 | 
						|||
| 
								 | 
							
															{
							 | 
						|||
| 
								 | 
							
																CollData->CollisionMeshToUpdate.Add(CollID);
							 | 
						|||
| 
								 | 
							
															}
							 | 
						|||
| 
								 | 
							
														}
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											for (const FName& TR : NameToRemove)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												CollData->UsedCollisionMesh.Remove(TR);
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											BrushRedraws.Empty();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											FBox WorldBounds = GBounds;
							 | 
						|||
| 
								 | 
							
											WorldBounds.Min *= 100.0;
							 | 
						|||
| 
								 | 
							
											WorldBounds.Max *= 100.0;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											//根据ShaderWorld边界,来维护UsedCollisionMesh、CollisionMeshData、CollisionMeshToCreate、CollisionMeshToRenameMoveUpdate、GroundCollisionLayout
							 | 
						|||
| 
								 | 
							
											for (auto& ExternalBounds : ExternalCollisionsBounds)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												FIntVector LocMeshInt = ExternalBounds;
							 | 
						|||
| 
								 | 
							
												FIntVector MeshLoc = LocMeshInt * CollisionWidth + FIntVector(0.f, 0.f, 1) * Height0 - LocalOriginLocation;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												if (Bounded && !WorldBounds.IntersectXY(FBox((FVector(LocMeshInt) - FVector(0.5, 0.5, 0.0)) * CollisionWidth, (FVector(LocMeshInt) + FVector(0.5, 0.5, 0.0)) * CollisionWidth)))
							 | 
						|||
| 
								 | 
							
													continue;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												if (!CollData->GroundCollisionLayout.Contains(LocMeshInt))
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													const FString CollisionMeshString = "SW_Collision_X_" + FString::FromInt(LocMeshInt.X) + "_Y_" + FString::FromInt(LocMeshInt.Y) + "_Z_" + FString::FromInt(LocMeshInt.Z);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													const FName CollisionMeshName = FName(*CollisionMeshString);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
													if (CollData->AvailableCollisionMesh.Num() > 0 && CollData->AvailableCollisionMesh.Contains(CollisionMeshName))
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														FSWCollisionMeshElemData& ElemData = *CollData->CollisionMeshData.Find(CollisionMeshName);
							 | 
						|||
| 
								 | 
							
														CollData->UsedCollisionMesh.Add(CollisionMeshName);
							 | 
						|||
| 
								 | 
							
														CollData->AvailableCollisionMesh.Remove(CollisionMeshName);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														ElemData.Location = LocMeshInt;
							 | 
						|||
| 
								 | 
							
														ElemData.MeshLocation = FVector(MeshLoc);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														CollData->CollisionMeshToRenameMoveUpdate.AddUnique(CollisionMeshName);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														CollData->GroundCollisionLayout.Add(LocMeshInt, CollisionMeshName);
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
													else
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														FCollisionMeshElement NewElem;
							 | 
						|||
| 
								 | 
							
														NewElem.ID = CollisionMeshName;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														NewElem.Location = LocMeshInt;
							 | 
						|||
| 
								 | 
							
														NewElem.MeshLocation = FVector(MeshLoc);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														CollData->UsedCollisionMesh.Add(CollisionMeshName);
							 | 
						|||
| 
								 | 
							
														CollData->CollisionMeshData.Add(CollisionMeshName, NewElem);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														CollData->CollisionMeshToCreate.AddUnique(CollisionMeshName);
							 | 
						|||
| 
								 | 
							
														CollData->CollisionMeshToRenameMoveUpdate.AddUnique(CollisionMeshName);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
														CollData->GroundCollisionLayout.Add(LocMeshInt, CollisionMeshName);
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											//根据ShaderWorld MultipleCamera,来维护UsedCollisionMesh、CollisionMeshData、CollisionMeshToCreate、CollisionMeshToRenameMoveUpdate、GroundCollisionLayout
							 | 
						|||
| 
								 | 
							
											for (auto& Elem : CollData->MultipleCamera)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												FIntVector& SingleCam = Elem.Key;
							 | 
						|||
| 
								 | 
							
												int32& LocalRingCount = Elem.Value;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												for (int r = LocalRingCount; r >= 0; r--)
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													for (int i = -r; i <= r; i++)
							 | 
						|||
| 
								 | 
							
													{
							 | 
						|||
| 
								 | 
							
														for (int j = -r; j <= r; j++)
							 | 
						|||
| 
								 | 
							
														{
							 | 
						|||
| 
								 | 
							
															if (abs(j) != r && abs(i) != r)
							 | 
						|||
| 
								 | 
							
																continue;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
															FIntVector LocMeshInt = FIntVector(SingleCam.X + i, SingleCam.Y + j, 0);
							 | 
						|||
| 
								 | 
							
															FIntVector MeshLoc = LocMeshInt * CollisionWidth + FIntVector(0.f, 0.f, 1) * Height0 - LocalOriginLocation;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
															if (Bounded && !WorldBounds.IntersectXY(FBox((FVector(LocMeshInt) - FVector(0.5, 0.5, 0.0)) * CollisionWidth, (FVector(LocMeshInt) + FVector(0.5, 0.5, 0.0)) * CollisionWidth)))
							 | 
						|||
| 
								 | 
							
																continue;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
															if (!CollData->GroundCollisionLayout.Contains(LocMeshInt))
							 | 
						|||
| 
								 | 
							
															{							
							 | 
						|||
| 
								 | 
							
																const FString CollisionMeshString = "SW_Collision_X_" + FString::FromInt(LocMeshInt.X) + "_Y_" + FString::FromInt(LocMeshInt.Y) + "_Z_" + FString::FromInt(LocMeshInt.Z);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
																const FName CollisionMeshName = FName(*CollisionMeshString);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
																if(CollData->AvailableCollisionMesh.Num() > 0 && CollData->AvailableCollisionMesh.Contains(CollisionMeshName))
							 | 
						|||
| 
								 | 
							
																{
							 | 
						|||
| 
								 | 
							
																	FSWCollisionMeshElemData& ElemData = *CollData->CollisionMeshData.Find(CollisionMeshName);
							 | 
						|||
| 
								 | 
							
																	CollData->UsedCollisionMesh.Add(CollisionMeshName);
							 | 
						|||
| 
								 | 
							
																	CollData->AvailableCollisionMesh.Remove(CollisionMeshName);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
																	ElemData.Location = LocMeshInt;
							 | 
						|||
| 
								 | 
							
																	ElemData.MeshLocation = FVector(MeshLoc);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
																	CollData->CollisionMeshToRenameMoveUpdate.AddUnique(CollisionMeshName);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
																	CollData->GroundCollisionLayout.Add(LocMeshInt, CollisionMeshName);
							 | 
						|||
| 
								 | 
							
																}
							 | 
						|||
| 
								 | 
							
																else
							 | 
						|||
| 
								 | 
							
																{
							 | 
						|||
| 
								 | 
							
																	FCollisionMeshElement NewElem;
							 | 
						|||
| 
								 | 
							
																	NewElem.ID = CollisionMeshName;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
																	NewElem.Location = LocMeshInt;
							 | 
						|||
| 
								 | 
							
																	NewElem.MeshLocation = FVector(MeshLoc);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
																	CollData->UsedCollisionMesh.Add(CollisionMeshName);
							 | 
						|||
| 
								 | 
							
																	CollData->CollisionMeshData.Add(CollisionMeshName, NewElem);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
																	CollData->CollisionMeshToCreate.AddUnique(CollisionMeshName);
							 | 
						|||
| 
								 | 
							
																	CollData->CollisionMeshToRenameMoveUpdate.AddUnique(CollisionMeshName);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
																	CollData->GroundCollisionLayout.Add(LocMeshInt, CollisionMeshName);
							 | 
						|||
| 
								 | 
							
																}								
							 | 
						|||
| 
								 | 
							
															}
							 | 
						|||
| 
								 | 
							
														}
							 | 
						|||
| 
								 | 
							
													}
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											//开始下一轮循环,bPreprocessingCollisionUpdate 设置为false
							 | 
						|||
| 
								 | 
							
											if (Completion.IsValid())
							 | 
						|||
| 
								 | 
							
												(*Completion.Get()) = false;
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
									);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### SpawnablesManagement()
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### TerrainAndSpawnablesManagement()
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								## PreEditChange() / PostEditChangeProperty()
							 | 
						|||
| 
								 | 
							
								**PreEditChange()** 主要针对以下两个变量的设置:
							 | 
						|||
| 
								 | 
							
								- PreventReRegistration:防止重新注册。
							 | 
						|||
| 
								 | 
							
								- RuntimePropertyEditing:实时属性修改。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								**PostEditChangeProperty()** 
							 | 
						|||
| 
								 | 
							
								里面比较关键的逻辑有:
							 | 
						|||
| 
								 | 
							
								- EditRebuildVegetation.AtomicSet(true);
							 | 
						|||
| 
								 | 
							
									- 在Setup()中清空Bioms数组。
							 | 
						|||
| 
								 | 
							
								- EditRebuild.AtomicSet(true);
							 | 
						|||
| 
								 | 
							
									- 在SetupCollisions()设置rebuild = true。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								如果RuntimePropertyEditing为true,在最后会将RuntimePropertyEditing设置为false。PreventReRegistration也会设置为false。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								## Rebuild变量
							 | 
						|||
| 
								 | 
							
								主要出现在:
							 | 
						|||
| 
								 | 
							
								- Setup():调用RebuildCleanup()清空所有数据。
							 | 
						|||
| 
								 | 
							
								- SetupCollision(): RedbuildCollisionContext = true。
							 | 
						|||
| 
								 | 
							
								- ProcessSpawnablePending():如果处于重建状态就直接返回。
							 | 
						|||
| 
								 | 
							
								- InitiateClipMapMeshes():如果处于重建状态就直接返回。
							 | 
						|||
| 
								 | 
							
								- FinalizeAsyncWork():如果处于重建状态就直接返回。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								## 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
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# 植被生成逻辑
							 | 
						|||
| 
								 | 
							
								Tick() => TerrainAndSpawnablesManagement() => UpdateSpawnables() => UpdateSpawnable()
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# 碰撞Python逻辑
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								```python
							 | 
						|||
| 
								 | 
							
								def TickCheckWorldReady(self, dt: float) -> bool:  
							 | 
						|||
| 
								 | 
							
								    is_shader_world_ready = self.ShaderWorldActor.WorldAndCollisionGeneratedReady()  
							 | 
						|||
| 
								 | 
							
								    if not is_shader_world_ready:  
							 | 
						|||
| 
								 | 
							
								        return True  
							 | 
						|||
| 
								 | 
							
								    is_ready = self.ShaderWorldActor.CheckCollisionGeneratedReady(self.AvatarBornPosition)  
							 | 
						|||
| 
								 | 
							
								    print("LBK --------  TickCheckWorldReady", self.FailedCheckCnt, is_ready)  
							 | 
						|||
| 
								 | 
							
								    if is_ready:  
							 | 
						|||
| 
								 | 
							
								        self.OnWorldMeshReady()  
							 | 
						|||
| 
								 | 
							
								        ue.RemoveTicker(self.worldTickHander)  
							 | 
						|||
| 
								 | 
							
								        # 等待地形物理加载完毕  
							 | 
						|||
| 
								 | 
							
								        if self.OtherLoadFinshed:  
							 | 
						|||
| 
								 | 
							
								            GlobalData.TimerSystem.AddTimer(1, self.ReallyStartDriving)  
							 | 
						|||
| 
								 | 
							
								        else:  
							 | 
						|||
| 
								 | 
							
								            self.OtherLoadFinshed = True  
							 | 
						|||
| 
								 | 
							
								        print('LBK -------------- DrivingModeSystem: TickCheckWorldReady', GlobalData.p.pos, self.AvatarBornPosition)  
							 | 
						|||
| 
								 | 
							
								        return False  
							 | 
						|||
| 
								 | 
							
								    self.FailedCheckCnt += 1  
							 | 
						|||
| 
								 | 
							
								    if self.FailedCheckCnt > self.FailedAttemptCnt:  #self.FailedAttemptCnt为40
							 | 
						|||
| 
								 | 
							
								        self.ShaderWorldActor.RebuildWorld()  
							 | 
						|||
| 
								 | 
							
								        self.FailedCheckCnt = 0  
							 | 
						|||
| 
								 | 
							
								    return True
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# 通过LineTraceSingleForObjects检测碰撞高度是否超过5,来判断碰撞是否生成。
							 | 
						|||
| 
								 | 
							
								def CheckCollisionGeneratedReady(self, checkPosition: ue.Vector) -> bool:  
							 | 
						|||
| 
								 | 
							
								    HitStartLocation = checkPosition + ue.Vector(0, 0, 50000.0)  
							 | 
						|||
| 
								 | 
							
								    HitEndLocation = checkPosition + ue.Vector(0, 0, -50000.0)  
							 | 
						|||
| 
								 | 
							
								    hitState, hitResult = ue.KismetSystemLibrary.LineTraceSingleForObjects(  
							 | 
						|||
| 
								 | 
							
								       self.GetWorld(),  
							 | 
						|||
| 
								 | 
							
								       HitStartLocation,  
							 | 
						|||
| 
								 | 
							
								       HitEndLocation,  
							 | 
						|||
| 
								 | 
							
								       [ue.EObjectTypeQuery.ObjectTypeQuery1, ue.EObjectTypeQuery.ObjectTypeQuery13],  # Ground  
							 | 
						|||
| 
								 | 
							
								       False,  # 是否追踪复杂碰撞  
							 | 
						|||
| 
								 | 
							
								       [],  
							 | 
						|||
| 
								 | 
							
								       ue.EDrawDebugTrace.ForDuration if GlobalData.IsDebugMode else ue.EDrawDebugTrace.NONE,  # 调试可视化  
							 | 
						|||
| 
								 | 
							
								       True,  # 忽略自身  
							 | 
						|||
| 
								 | 
							
								       ue.LinearColor(1.0, 0.0, 0.0, 1.0),  # 红色  
							 | 
						|||
| 
								 | 
							
								       ue.LinearColor(0.0, 1.0, 0.0, 1.0),  # 绿色  
							 | 
						|||
| 
								 | 
							
								       20.0  # 调试线条持续时间  
							 | 
						|||
| 
								 | 
							
								    )  
							 | 
						|||
| 
								 | 
							
								    if not hitState:  
							 | 
						|||
| 
								 | 
							
								       return False  
							 | 
						|||
| 
								 | 
							
								    # TODO LBK 这个射线检测的方式不太准确,那个物理生成,会从平面开始  
							 | 
						|||
| 
								 | 
							
								    return hitResult.Location.Z > 5.0
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								bool AShaderWorldActor::WorldAndCollisionGeneratedReady()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									if (!WorldGeneratedAndReady())
							 | 
						|||
| 
								 | 
							
										return false;
							 | 
						|||
| 
								 | 
							
									if (!CollisionShareable.IsValid())
							 | 
						|||
| 
								 | 
							
										return false;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									FScopeLock CollisionMeshArrayAccess(CollisionMeshAccessLock.Get());
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// 1. 必须有碰撞布局
							 | 
						|||
| 
								 | 
							
									if (CollisionShareable->GroundCollisionLayout.Num() == 0)
							 | 
						|||
| 
								 | 
							
										return false;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// 2. 检查所有Patch都ready
							 | 
						|||
| 
								 | 
							
									for (const auto& Pair : CollisionShareable->GroundCollisionLayout)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										const FIntVector& Loc = Pair.Key;
							 | 
						|||
| 
								 | 
							
										const FName& CollisionName = Pair.Value;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										// Patch必须存在
							 | 
						|||
| 
								 | 
							
										if (!CollisionMesh.Contains(CollisionName))
							 | 
						|||
| 
								 | 
							
											return false;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										// Patch必须在已用集合
							 | 
						|||
| 
								 | 
							
										if (!CollisionShareable->UsedCollisionMesh.Contains(CollisionName))
							 | 
						|||
| 
								 | 
							
											return false;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										// Patch必须ReadBack完成
							 | 
						|||
| 
								 | 
							
										const FCollisionMeshElement& CollisionElement = *CollisionMesh.Find(CollisionName);
							 | 
						|||
| 
								 | 
							
										if (!CollisionElement.ReadBackCompletion.IsValid() || !(*CollisionElement.ReadBackCompletion.Get()))
							 | 
						|||
| 
								 | 
							
											return false;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										// Patch不能在待处理队列
							 | 
						|||
| 
								 | 
							
										if (CollisionReadToProcess.Contains(CollisionName))
							 | 
						|||
| 
								 | 
							
											return false;
							 | 
						|||
| 
								 | 
							
										if (!UsedCollisionMesh.Contains(CollisionName))
							 | 
						|||
| 
								 | 
							
											return false;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										// Patch不能在工作队列
							 | 
						|||
| 
								 | 
							
										for (const auto& WQ : CollisionWorkQueue)
							 | 
						|||
| 
								 | 
							
											if (WQ.MeshID == CollisionName)
							 | 
						|||
| 
								 | 
							
												return false;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									return true;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 |