From 655dc2076ffd9e61961df104d68bef6ac52946d3 Mon Sep 17 00:00:00 2001 From: BlueRose <378100977@qq.com> Date: Tue, 15 Jul 2025 19:06:28 +0800 Subject: [PATCH] vault backup: 2025-07-15 19:06:28 --- .../ShaderWorldPlugin/ShaderWorld.md | 1011 ++++++++++++++++- 1 file changed, 1005 insertions(+), 6 deletions(-) diff --git a/03-UnrealEngine/Rendering/RenderFeature/ShaderWorldPlugin/ShaderWorld.md b/03-UnrealEngine/Rendering/RenderFeature/ShaderWorldPlugin/ShaderWorld.md index a63e781..dc1ce95 100644 --- a/03-UnrealEngine/Rendering/RenderFeature/ShaderWorldPlugin/ShaderWorld.md +++ b/03-UnrealEngine/Rendering/RenderFeature/ShaderWorldPlugin/ShaderWorld.md @@ -171,6 +171,16 @@ void AShaderWorldActor::ReadbacksManagement() - 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) { @@ -210,9 +220,11 @@ void AShaderWorldActor::CollisionManagement(float& DeltaT) CollisionGPU(); // Timer + // 碰撞生成与Update计时 { CollisionUpdateTimeAcu += DeltaT; + //CollisionUpdateTimeAcu如果超过0.1s,或者CollisionWorkQueue的任务都完成了。CollisionProcess已经完成。 if (CollisionUpdateTimeAcu <= 1.f / 10.f || CollisionWorkQueue.Num() > 0 || !CollisionProcess.IsFenceComplete()) return; @@ -280,6 +292,7 @@ bool AShaderWorldActor::SetupCollisions() if (!GenerateCollision) return false; + //创建全线程碰撞生成相关数据结构体CollisionShareable if (!CollisionShareable.IsValid()) CollisionShareable = MakeShared(CollisionResolution, CollisionVerticesPerPatch); @@ -652,7 +665,6 @@ void AShaderWorldActor::CollisionGPU() double CurrentTime = FPlatformTime::Seconds(); - if (!(!(*bPreprocessingCollisionUpdate.Get()) && ( CollisionShareable->CollisionMeshToUpdate.Num() > 0 || CollisionShareable->CollisionMeshToRenameMoveUpdate.Num() > 0 || @@ -674,7 +686,7 @@ void AShaderWorldActor::CollisionGPU() //更新时间戳 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()))) + 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(); @@ -725,12 +737,14 @@ void AShaderWorldActor::CollisionGPU() /* * 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); + FCollisionMeshElement& Mesh = GetACollisionMesh(ID);//GetACollisionMesh()取得现有FCollisionMeshElement或者创建新的,代码贼长。 Mesh.Location = Mesh_Shareable.Location; Mesh.MeshLocation = Mesh_Shareable.MeshLocation; @@ -740,14 +754,15 @@ void AShaderWorldActor::CollisionGPU() 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); + UpdateCollisionMeshData(El);//核心函数 CollisionShareable->CollisionMeshToUpdate.RemoveAt(i); @@ -758,6 +773,7 @@ void AShaderWorldActor::CollisionGPU() break; } + //处理CollisionMeshToRenameMoveUpdate 碰撞数据重命名&移动更新队列 for (int i = CollisionShareable->CollisionMeshToRenameMoveUpdate.Num() - 1; i >= 0; i--) { FName& CollisionIDToUpdate = CollisionShareable->CollisionMeshToRenameMoveUpdate[i]; @@ -784,6 +800,7 @@ void AShaderWorldActor::CollisionGPU() break; } + //开启CollisionProcess,需要等到执行完之后,才能执行CollisionPreprocessGPU() if (RequireRenderFence) { CollisionProcess.BeginFence(); @@ -792,8 +809,681 @@ void AShaderWorldActor::CollisionGPU() } ``` -### ```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(); + NewElem.HeightData->ReadData.SetNum(CollisionVerticesPerPatch * CollisionVerticesPerPatch); + + NewElem.Mesh = NewObject(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 Vertices = MakeShared(); + TSharedPtr Triangles = MakeShared(); + + 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 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(); + 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 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(); + 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 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(); + 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(); + 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(); + 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 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(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(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(); + Mesh.HeightData->ReadData.SetNum(CollisionVerticesPerPatch * CollisionVerticesPerPatch); + } + + if (!Mesh.ReadBackCompletion.IsValid()) + { + Mesh.ReadBackCompletion = MakeShared(); + } + + //设置 碰撞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); @@ -804,6 +1494,315 @@ void AShaderWorldActor::CollisionCPU() 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 BrushRedrawScope; + + if (bBrushManagerAskedRedraw) + { + BrushRedrawScope = MoveTemp(BrushManagerRedrawScopes_collision); + BrushManagerRedrawScopes_collision.Empty(); + } + + + + bool bExternalCollisionRebuildRequest = !CollisionUpdateRequest.IsEmpty(); + FBox2D BPCollisionRebuildRequest(ForceInit); + + if (bExternalCollisionRebuildRequest) + CollisionUpdateRequest.Dequeue(BPCollisionRebuildRequest); + + TArray VisitorLocations; + + // Use latest camera we know if current array is empty + + if (CameraLocations.Num() <= 0) + VisitorLocations.Add(CamLocation); + + VisitorLocations.Append(CameraLocations); + + (*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] + { + if (!CollData.IsValid()) + { + if (Completion.IsValid()) + (*Completion.Get()) = false; + return; + } + + FScopeLock CollisionMeshArrayAccess(Lock.Get()); + + double CollisionWidth = CollData->CollisionResolution * (CollData->VerticePerPatch - 1); + + TMap 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 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(); + + 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 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; + + 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); + } + } + } + + 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); + } + } + } + } + } + } + + if (Completion.IsValid()) + (*Completion.Get()) = false; + } + ); +} ``` ### SpawnablesManagement()