diff --git a/.obsidian/plugins/various-complements/histories.json b/.obsidian/plugins/various-complements/histories.json index 7b56615..a797291 100644 --- a/.obsidian/plugins/various-complements/histories.json +++ b/.obsidian/plugins/various-complements/histories.json @@ -1 +1 @@ -{"Class":{"Class":{"currentFile":{"count":1,"lastUpdated":1748942840437}}},"DebugView":{"DebugView":{"internalLink":{"count":1,"lastUpdated":1749700323505}}},"XXXXX,之后点击回车。注:XXXXX为模拟器端口号,请参考打开的模拟器问题诊断内展示端口号或MuMu多开器12内的adb端口后再输入。":{"XXXXX,之后点击回车。注:XXXXX为模拟器端口号,请参考打开的模拟器问题诊断内展示端口号或MuMu多开器12内的adb端口后再输入。":{"currentFile":{"count":1,"lastUpdated":1750142832492}}},"\\Users\\loujiajie\\desktop\\log.txt":{"\\Users\\loujiajie\\desktop\\log.txt":{"currentFile":{"count":1,"lastUpdated":1750143148509}}},"相关线程安全变量:":{"相关线程安全变量:":{"currentFile":{"count":1,"lastUpdated":1750853529118}}}} \ No newline at end of file +{"DebugView":{"DebugView":{"internalLink":{"count":1,"lastUpdated":1749700323505}}},"XXXXX,之后点击回车。注:XXXXX为模拟器端口号,请参考打开的模拟器问题诊断内展示端口号或MuMu多开器12内的adb端口后再输入。":{"XXXXX,之后点击回车。注:XXXXX为模拟器端口号,请参考打开的模拟器问题诊断内展示端口号或MuMu多开器12内的adb端口后再输入。":{"currentFile":{"count":1,"lastUpdated":1750142832492}}},"\\Users\\loujiajie\\desktop\\log.txt":{"\\Users\\loujiajie\\desktop\\log.txt":{"currentFile":{"count":1,"lastUpdated":1750143148509}}},"相关线程安全变量:":{"相关线程安全变量:":{"currentFile":{"count":1,"lastUpdated":1750853529118}}},"UBodySetup":{"UBodySetup":{"currentFile":{"count":1,"lastUpdated":1750994347070}}},"Android常用命令":{"Android常用命令":{"internalLink":{"count":1,"lastUpdated":1751942017728}}}} \ No newline at end of file diff --git a/03-UnrealEngine/Rendering/RenderFeature/ShaderWorldPlugin/ShaderWorld.md b/03-UnrealEngine/Rendering/RenderFeature/ShaderWorldPlugin/ShaderWorld.md index cad54f2..dc1ce95 100644 --- a/03-UnrealEngine/Rendering/RenderFeature/ShaderWorldPlugin/ShaderWorld.md +++ b/03-UnrealEngine/Rendering/RenderFeature/ShaderWorldPlugin/ShaderWorld.md @@ -16,9 +16,6 @@ rating: ⭐ - ShaderWorldActor.h:[[#AShaderWorldActor]] - SWorld.h:[[#ASWorld]] -## FRenderCommandFence - - # USWorldSubsystem 主要管理: - TArray SW_Contexts @@ -158,7 +155,7 @@ void AShaderWorldActor::ReadbacksManagement() ### CollisionManagement() - ThreadSafe - bool - - bProcessingGroundCollision + - ***bProcessingGroundCollision***:处理地面碰撞。 - bPreprocessingCollisionUpdate - EditRebuild:传递Bool值给 rebuild。 - FSWCollisionManagementShareableData @@ -168,8 +165,20 @@ void AShaderWorldActor::ReadbacksManagement() - bool - RedbuildCollisionContext - Array - - CollisionWorkQueue:类型为FCollisionProcessingWork。 - - CollisionReadToProcess + - 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++ @@ -211,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; @@ -230,6 +241,7 @@ void AShaderWorldActor::CollisionManagement(float& DeltaT) ``` #### SetupCollisions() +设置相关变量。 ```c++ bool AShaderWorldActor::SetupCollisions() { @@ -280,6 +292,7 @@ bool AShaderWorldActor::SetupCollisions() if (!GenerateCollision) return false; + //创建全线程碰撞生成相关数据结构体CollisionShareable if (!CollisionShareable.IsValid()) CollisionShareable = MakeShared(CollisionResolution, CollisionVerticesPerPatch); @@ -310,15 +323,18 @@ bool AShaderWorldActor::SetupCollisions() } ``` -#### CollisionFinalizeWork() -判断碰撞生成是否已经完成。 +#### CollisionFinalizeWork() 笔记为3.8.6版本非最新 +结束碰撞生成任务,true为完成,false为任务超时未完成。**主要的逻辑是将之前的数据设置为脏,并且更新FShaderWProceduralMeshSceneProxy,5.4 Finaly版本里这里已经移除了碰撞相关逻辑** +- TMap 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; @@ -326,6 +342,7 @@ bool AShaderWorldActor::CollisionFinalizeWork() double TimeStart = FPlatformTime::Seconds(); + //判断处理队列是否为空 if(CollisionWorkQueue.Num()<=0) return true; @@ -333,26 +350,1461 @@ bool AShaderWorldActor::CollisionFinalizeWork() 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& 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, ESPMode::ThreadSafe> Normals = SWComputeNormalsForPatch(PBuffer, IndexB); + + AsyncTask(ENamedThreads::GameThread, [WeakThis,PBuffer, Normals]() + { + if (WeakThis.IsValid()) + { + if (UShaderWorldCollisionComponent* Comp = Cast(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(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& 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(); + + 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 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(); + 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); + 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 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() ### TerrainAndSpawnablesManagement() @@ -784,3 +2236,101 @@ OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZEZ"), 1); # 植被生成逻辑 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; +} +``` \ No newline at end of file diff --git a/03-UnrealEngine/卡通渲染相关资料/卡通渲染开发总览.md b/03-UnrealEngine/卡通渲染相关资料/卡通渲染开发总览.md index a033221..0c9809d 100644 --- a/03-UnrealEngine/卡通渲染相关资料/卡通渲染开发总览.md +++ b/03-UnrealEngine/卡通渲染相关资料/卡通渲染开发总览.md @@ -164,11 +164,16 @@ rating: ⭐⭐⭐ 3. [ ] [GDC2025 : Generalized Stylized Post Processing Outline](https://zhuanlan.zhihu.com/p/1895785690161198348) 16. [ ] [[Toon多光源参考|Toon多光源后处理Pass]] 17. [ ] [【虚幻5】UE_动画变形工具(晶格变形)](https://www.bilibili.com/video/BV1DsR3YoEML/?share_source=copy_web&vd_source=fe8142e8e12816535feaeabd6f6cdc8e) -18. [ ] 月下幻影的掰法线思路:`N = _Scale * NoL * L + N`尝试找到使用场景。资产路径`/Game/ToonContentExample/MaterialUtility/NormalOffsetToDirectionalLight/M_NormalOffsetToDirectionalLight` -19. [ ] RGS 光线追踪与路径追踪支持。 +18. [ ] +19. [ ] 掰法线相关 + 1. [ ] 【Blender插件 Easy Custom Normals V1.1.0汉化版,卡通渲染优化利器!-哔哩哔哩】 https://b23.tv/meLiEkj + 1. [ ] https://superhivemarket.com/products/stylized-normals + 2. [ ] https://tools.fondant.gg/ + 2. [ ] 月下幻影的掰法线思路:`N = _Scale * NoL * L + N`尝试找到使用场景。资产路径`/Game/ToonContentExample/MaterialUtility/NormalOffsetToDirectionalLight/M_NormalOffsetToDirectionalLight` +20. [ ] RGS 光线追踪与路径追踪支持。 1. [ ] [【UE5】通过Raytracing自定义卡通渲染投影](https://zhuanlan.zhihu.com/p/688722298) https://zhuanlan.zhihu.com/p/688722298 -20. [ ] 给EditorView添加卡通渲染用场景,默认场景的渲染效果对不上。 -21. [ ] 实现前向混合管线?思路有2:1. Material直接计算光照结果。2. 自定义ToonBasePass到LightingPass后,复制阴影贴图与Lumen渲染结果进行Composition。 +21. [ ] 给EditorView添加卡通渲染用场景,默认场景的渲染效果对不上。 +22. [ ] 实现前向混合管线?思路有2:1. Material直接计算光照结果。2. 自定义ToonBasePass到LightingPass后,复制阴影贴图与Lumen渲染结果进行Composition。 1. 原神早期的方案: 1. 渲染地形(远景 2. @@ -179,37 +184,37 @@ rating: ⭐⭐⭐ 6. 渲染深度与法线Buffer。 7. 渲染级联阴影。 8. 合成,阴影与环境光照(AO、环境探针)。 -22. [ ] 云彩生成器 +23. [ ] 云彩生成器 1. [ ] https://www.bilibili.com/video/BV1L5kdYFEXc/?spm_id_from=333.1007.tianma.4-1-11.click&vd_source=d47c0bb42f9c72fd7d74562185cee290 2. [ ] 风格化水面资产 https://item.taobao.com/item.htm?id=865360489543&pisk=gLHsX7NMiNb1gB7njFKURXly5Dwb5q9y1iZxqmBNDReTkigKDtQA6-FLJorOMSU2sqNju2VxQRoZRGDIPtWwSCmAh-yvzUJyUcman-Lyk8kOUGq4mNUAurCKv-rjPdNAXcmgnrIFkQlKjZg5RK5YDrKQpor7k-EYW9KQcuaYHPFAJ6E8JrexkSIdJuZ5MZCTHkKQju5OBoeYvMEaVtBtk-KIvyqxnDXQDCZ-fHz1qUDkpeKgJtBxdlNpTcUKrr-4i5TjbyXvy1Zg1coTRtBxKXkPllz9ZMz0QPDbfqvlIRFjTAVoQeBsl20KBSDp8B00QuV-MD-lTPDIQvFsCU1uCX3nd5DOWhqtsqDbQx71hDMb57HTOKx0CDEYdbneq6zidAkL1AT5ZPMiDjPItNTUuboEBWgJ89g0GXkgZA8dC4IyzTz7sJ5fA7XbAz-BAsf0xzPwqJ_edaNTxlTyAH_Gi5E3AmtBAsDg6kqF6HtCWc1..&spm=a21xtw.29178619.product_shelf.74.41727d6dRCDvul -23. [ ] 添加Debug View https://zhuanlan.zhihu.com/p/668782106 -24. [ ] [_UE5_ Shader Print系统](https://zhuanlan.zhihu.com/p/637929634) -25. [ ] GBufferView实现。 -26. [ ] Toon Debug模式,可以让美术在材质进行进行简单的光照计算。 -27. [ ] ToonShadow +24. [ ] 添加Debug View https://zhuanlan.zhihu.com/p/668782106 +25. [ ] [_UE5_ Shader Print系统](https://zhuanlan.zhihu.com/p/637929634) +26. [ ] GBufferView实现。 +27. [ ] Toon Debug模式,可以让美术在材质进行进行简单的光照计算。 +28. [ ] ToonShadow 1. ![[星穹铁道中下巴阴影处理.png]] 2. [ ] ToonSDFShadow 1. [ ] TODO: SDF贴图工具? -28. [ ] LookDev场景 +29. [ ] LookDev场景 1. [ ] https://zhuanlan.zhihu.com/p/394608910 -29. [ ] 考虑往GBuffer中添加更多数据(考虑Velocity以及SingleLayerWater) +30. [ ] 考虑往GBuffer中添加更多数据(考虑Velocity以及SingleLayerWater) 1. ShaderMaterialDerivedHelpers.cpp(Shader宏)、GBufferInfo.cpp(GBuffer格式)BasePassRendering.cpp(950行,SingleLayerWater写入GBuffer格式相关) 2. 确定一下SingleLayerWater中VSMFiter与DistanceFieldShadow对渲染结果的影响,之后在文档中说明。 -30. [ ] 修复SIngleLayerWater的缩略图渲染渲染错误(双击会有一瞬间的错误产生) -31. [ ] 添加对应的Stat https://zhuanlan.zhihu.com/p/716644594 -32. [ ] ToonLumen、GI以及晕染效果实现。![[卡通渲染晕染效果.mp4]] -33. [ ] 在材质中实现ToonEye相关效果 +31. [ ] 修复SIngleLayerWater的缩略图渲染渲染错误(双击会有一瞬间的错误产生) +32. [ ] 添加对应的Stat https://zhuanlan.zhihu.com/p/716644594 +33. [ ] ToonLumen、GI以及晕染效果实现。![[卡通渲染晕染效果.mp4]] +34. [ ] 在材质中实现ToonEye相关效果 1. 【二次元人物眼睛如何变形?】 https://www.bilibili.com/video/BV14M4m1y71A/?share_source=copy_web&vd_source=fe8142e8e12816535feaeabd6f6cdc8e 1. 原视频 https://www.youtube.com/watch?v=euIyX9v8rvw 2. 眼睛建模 https://youtu.be/s2_7Q2IIvNY?si=fWiYjqcLFXzdeQ-B&t=126 -34. 尝试实现Forward+ +35. 尝试实现Forward+ 1. BasePass https://zhuanlan.zhihu.com/p/618698467 -35. DX11问题修复 +36. DX11问题修复 1. [x] ToonOutline SceneColorTexture为空的问题。 **DX11限制,必须CopyTexture** -36. 卡通渲染针对TAA的优化思路 https://zhuanlan.zhihu.com/p/678876237 +37. 卡通渲染针对TAA的优化思路 https://zhuanlan.zhihu.com/p/678876237 1. https://www.bilibili.com/video/BV1BK411v7FY/?spm_id_from=333.788&vd_source=ea6df38502a795b7533aa33b78bf1159 2. https://zhuanlan.zhihu.com/p/20786650 -37. [ ] Unreal Engine 5.4 Scene Extension https://zhuanlan.zhihu.com/p/706268007 +38. [ ] Unreal Engine 5.4 Scene Extension https://zhuanlan.zhihu.com/p/706268007 1. [ ] 通过SceneExtension改进ToonObjectID,这样可以减少对应ToonBuffer的精度来存其他数据。 2. [ ] https://www.bilibili.com/video/BV1fM4m1U7Tp/ diff --git a/03-UnrealEngine/性能优化/UltraDynamicSky的UDS_PlayerOcclusion 组件性能问题.md b/03-UnrealEngine/性能优化/UltraDynamicSky的UDS_PlayerOcclusion 组件性能问题.md new file mode 100644 index 0000000..72a0185 --- /dev/null +++ b/03-UnrealEngine/性能优化/UltraDynamicSky的UDS_PlayerOcclusion 组件性能问题.md @@ -0,0 +1,12 @@ +--- +title: Untitled +date: 2025-07-08 10:29:19 +excerpt: +tags: +rating: ⭐ +--- +# Init +该组件在ConstructionScript() -> ConstructionScriptFunction() -> AddConstructedCompoents() -> AddUDSPlayerOcclusion中被创建。 +创建完之后调用UDS_PlayerOcclusion组件的Initialize()完成初始化。 + +