BlueRoseNote/03-UnrealEngine/LevelScene/WorldPartition(世界分区).md

202 lines
16 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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

---
title: World Partition(世界分区)
date: 2024-04-26 14:18:36
excerpt:
tags:
rating: ⭐
---
# 前言
文档地址: https://dev.epicgames.com/documentation/en-us/unreal-engine/world-partition-in-unreal-engine?application_version=5.3
- 知乎文章:
- UE5
- UE5 World Partition不完全指南:https://zhuanlan.zhihu.com/p/687020988
- UE4
- UE4旧版方案WorldComposition https://zhuanlan.zhihu.com/p/270172506
- UE4场景流送机制场景加载 https://zhuanlan.zhihu.com/p/269493281
- UE4场景流送机制LevelStreamingVolume&WorldComposition https://zhuanlan.zhihu.com/p/270172506
PS.可以使用Tools-Convert Level或者World Partition Convert Commandlet对普通关卡来进行转换。
## 调试命令
- 图形化Debug显示
- wp.Runtime.ToggleDrawRuntimeHash2D
- wp.Runtime.ToggleDrawRuntimeHash3D
| | |
|---|---|
|**wp.Runtime.ToggleDrawRuntimeHash2D**|开关世界分区运行时哈希的2D调试显示。|
|**wp.Runtime.ToggleDrawRuntimeHash3D**|开关世界分区运行时哈希的3D调试显示。|
|**wp.Runtime.ShowRuntimeSpatialHashGridLevel**|选择在显示世界分区运行时哈希时显示的网格级别。|
|**wp.Runtime.ShowRuntimeSpatialHashGridLevelCount**|选择在显示世界分区运行时哈希时要显示多少个网格级别。|
|**wp.Runtime.ShowRuntimeSpatialHashGridIndex**|显示世界分区运行时哈希时,显示指定的网格。无效的索引将导致显示所有网格。|
|**wp.Runtime.RuntimeSpatialHashCellToSourceAngleContributionToCellImportance**|取0到1之间的值用于调节"流送源-单元网格"向量和"流送源-单元网格"向量之间的角度对单元网格重要性的贡献。该值越接近于0角度对重要性的贡献就越小。|
|**wp.Runtime.OverrideRuntimeSpatialHashLoadingRange**|设置运行时加载范围。接受以下参数:<br><br>- `-grid=[index]`:设置你想影响的运行时网格。<br>- `-range=[override_loading_range]`: 设置新的运行时加载范围|
|**wp.Runtime.MaxLoadingLevelStreamingCells**|限制并发加载的世界分区流单元的数量。|
|**wp.Runtime.HLOD 0**|使用 `wp.Runtime.HLOD` 显示没有HLOD的世界。|
# 关卡实例化
这2个选项在Actor右键菜单中ActorSelection
- **Level Instance**
- 可以将任意Actor塞进去
- 采用**OFPA**系统保存关卡信息
- **Packed Level Actor**
- 继承自Level Instance
- 将所选的Actor变为component在创建Level的同时创建一个Blueprint
- 内部Actor不再使用**OFPA**的方式同时意味着整个Packed Level Actor只会按整体流送
- 在Pack时只会打包场景资产类型功能性的蓝图会被排除
***相关说明文章***:https://dev.epicgames.com/community/learning/knowledge-base/r6wl/unreal-engine-world-building-guide
# 官方文档阅读笔记
## 概念
- **流送源**[[#PlayerController]]是一种流送源,其他流送源可以使用 **世界分区流送源组件UWorldPartitionStreamingSourceComponent** 添加到关卡中使得加载指定位置的Grid。
- [[#DataLayer]]是世界分区系统中的一个子系统用于将Actor划分到单独的层中。通过加载和卸载数据层
## 将现有关卡转换为使用世界分区
 可以使用**工具Tools> 转换关卡Convert Level** 菜单选项或使用世界分区转换命令:
`UnrealEditor.exe 项目名称 -run=WorldPartitionConvertCommandlet Playground.umap -AllowCommandletRendering`
## 相关设置
### WorldSettings
- **启用流送Enable Streaming**: 选项启用和禁用网格单元流送。
- 使用MovieRenderQueue进行渲染时需要关闭这个选项不然场景不会加载。
- ***Use External Actors***为整个Level启用每个Actor per File存储方式。
- Preview Grid可以在Viewport中大致预览一下每个Grid对应的Cell Size和Loading Range的设置是否合理。Preview Gird Level可以修改预览层级。
| | |
| ------------------------------------- | ----------------------------------------------------------------- |
| **网格名称Grid Name** | 包含运行时网格的名称。 |
| **单元大小Cell Size** | 确定用于生成流送关卡的网格单元的大小。在示例中, **单元大小Cell Size** 是256平方米。 |
| **加载范围Loading Range** | 确定与流送源距离多远的范围之内会加载单元。在上图中, **加载范围Loading Range** 是流送源周围768米的半径。 |
| **在缓慢流送时阻止Block on Slow Streaming** | 在网格单元加载速度不够快的情况下阻止加载。 |
| **优先级Priority** | 确定流送源的优先级。如果某个网格单元与多个流送源相交,其优先级将是所有流送源中最高的。 |
| **调试颜色Debug Color** | 确定启用 **预览网格Preview Grids** 时显示的网格线颜色。 |
| **预览网格Preview Grids** | 启用时,将在视口中显示网格线。 |
### Actor
- Runtime Grid用于指定Actor的分区Grid名称如果**没有指定则会自动选择**。
- Is Spatially Loaded
- 如果启用此Actor在未分配到禁用的数据层且在任何流送源的范围内时加载。
- 如果禁用此Actor在未分配到禁用的数据层时加载。
- Packaging Mode选择是否将Actor设置成Actor Per File存储方式。
### PlayerController
- Enable Streaming Source将控制器作为作为**流送源**。
### UWorldPartitionStreamingSourceComponent
| | |
| ------------------------------------------------ | -------------------------------------------------------------------- |
| **默认可视化器加载范围Default Visualizer Loading Range** | 确定启用可视化器时调试可视化器网格的大小。 |
| **目标网格Target Grid** | 确定此源影响的流送网格。 |
| **调试颜色Debug Color** | 确定用于调试的颜色。 |
| **目标HLOD层Target HLOD Layer** | 确定流送源影响的HLOD层。 |
| **形状Shapes** | 确定用于为此流送源构建自定义形状的形状列表。如果为空,将使用半径等于网格加载范围的球体。 |
| **优先级Priority** | 确定流送源的优先级。如果某个网格单元与多个流送源相交,其优先级将是所有流送源中最高的。 |
| **流送源已启用Streaming Source Enabled** | 确定此组件是否已启用。 |
| **目标状态Target State** | 确定相交的网格单元应该处于的状态(已加载或已激活)。如果某个网格单元与多个流送源相交,目标状态将是最高的目标值(其中已激活高于已加载)。 |
蓝图函数 **Enable Streaming Source** 和 **Disable Streaming Source** 将启用和禁用此组件的流送。
### ALocationVolume
一种用于**加载/卸载** 指定区域的Volumn。可以在WorldPartition编辑器上点击来进行控制。也有三个蓝图函数用于控制加载与卸载
- void Load()
- void Unload()
- bool IsLoaded() const
## 构建WorldPartition编辑器小地图
Build - Build Minimap
## DataLayer
官方文档:https://dev.epicgames.com/documentation/zh-cn/unreal-engine/world-partition---data-layers-in-unreal-engine?application_version=5.2
![[WorldPartition_LayerData.png|400]]
| | |
| ----- | ----------------------------------------------------------------------------------------- |
| **1** | 在关卡编辑器中切换关卡的可视性。仅当某个Actor所有关联数据层都隐藏时它才能被隐藏。 |
| **2** | 表示"动态加载Is Dynamically Loaded"的状态。动态加载的层将会影响运行时的Actor加载。可以使用蓝图或C++代码激活这些层。 |
| **3** | 切换"编辑器动态加载Editor Dynamically Loaded"标记。在关卡编辑器中如果Actor启用了数据层并且在世界分区中加载了编辑器单元格将加载Actor。 |
| **4** | 切换此数据层中所有Actor的可见情况 |
| **5** | 决定启动时数据层是否在编辑器中显示。 |
| **6** | 决定是否应该为此数据层中的Actor生成HLOD。仅当启用"动态加载Is Dynamically Loaded"时可用。 |
| **7** | 决定启用了"动态加载Is Dynamically Loaded"的数据层在运行时加载、卸载还是激活。 |
| **8** | 决定数据层是否影响Actor的运行时加载。 |
***默认只在Editor下生效可以将其类型切换为Runtime从而使其在游戏过程中也可以通过逻辑控制某一Layer的显隐。***
### 使用蓝图或者c++控制DataLayer加载
通过**UDataLayerSubsystem**的SetDataLayerState()来控制DataLayer的加载与卸载。
相关的Runtime加载控制可以参考:https://youtu.be/LI6TsZf5hh0?si=nwqz-S6DDR7MgSBT
直接通过蓝图的DataLayerSubsystem进行控制加载与显示。
# 相关CommandLet
- 烘焙WorldPartitionUnrealEditor.exe QAGame -run=cook -targetplatform=WindowsNoEditor -Unversioned -map=Playground
- HLOD Build`UnrealEditor.exe "C:\Users\user.name\Documents\Unreal Projects\MyProject\MyProject.uproject" "/Game/ThirdPersonBP/Maps/OpenWorldTest" -run=WorldPartitionBuilderCommandlet -AllowCommandletRendering -builder=WorldPartitionHLODsBuilder`
- WorldPartition重命名复制`UnrealEditor.exe "C:\Users\user.name\Documents\Unreal Projects\MyProject\MyProject.uproject" "/Game/ThirdPersonBP/Maps/OpenWorldTest" -run=WorldPartitionBuilderCommandlet -SCCProvider=None -builder=WorldPartitionRenameDuplicateBuilder -NewPackage=/Game/ThirdPersonBP/Maps/NewPackage`
- WorldPartition重新保存Actor`UnrealEditor.exe "C:\Users\user.name\Documents\Unreal Projects\MyProject\MyProject.uproject" "/Game/ThirdPersonBP/Maps/OpenWorldTest" -run=WorldPartitionBuilderCommandlet -SCCProvider=None -builder=WorldPartitionResaveActorsBuilder`
- WorldPartition植被构建`UnrealEditor.exe QAGame Playground.umap -run=WorldPartitionBuilderCommandlet -Builder=WorldPartitionFoliageBuilder -NewGridSize=Value`
- WorldPartition Nav构建`UnrealEditor.exe "C:\Users\user.name\Documents\Unreal Projects\MyProject\MyProject.uproject" "/Game/ThirdPersonBP/Maps/OpenWorldTest" -run=WorldPartitionBuilderCommandlet -AllowCommandletRendering -builder=WorldPartitionNavigationDataBuilder -SCCProvider=None`
- WorldPartition智能对象构建 `UnrealEditor.exe "C:\Users\user.name\Documents\Unreal Projects\MyProject\MyProject.uproject" "/Game/ThirdPersonBP/Maps/OpenWorldTest" -run=WorldPartitionBuilderCommandlet -builder=WorldPartitionSmartObjectCollectionBuilder`
- 转换子关卡为WorldPartition`UnrealEditor.exe -run=ConvertLevelsToExternalActorsCommandlet -nosourcecontrol -convertsublevels "Game/Maps/TestMaps/ExternalActors/MainMap`
# 修改WorldPartition场景中出现已删除物体的物体问题
猜测执行WorldPartitionBuilderCommandlet -builder=WorldPartitionResaveActorsBuilder。还未经过测试。
```bash
cd /d D:
cd D:\Projects\ASoul_UE5\Engine\Engine\Binaries\Win64
UnrealEditor.exe "D:\Projects\ASoul_UE5\LiveDirector\LiveDirector.uproject" "/Game/Maps/Map_WuTai_WP/Map_WuTai_WP" -run=WorldPartitionBuilderCommandlet -SCCProvider=None -builder=WorldPartitionResaveActorsBuilder
```
统计文件数量
p4 sizes -s //Project/Development/LiveDirector/Content/__ExternalActors__/Maps/Map_WuTai_WP/Map_WuTai_WP/...
# WorldPartition Runtime Sequence驱动物体问题
1. WorldSettings关闭 EnableStreaming。所有场景Actor都会一直加载。
2. 对应Actor关闭Is Spatially LoadedActor会一直加载。
3. ~~使用WorldPartitionRuntimeStateVolumn设置DataLayer加载即可。~~ 经过测试无效
4. ~~Sequence使用DataLayerTracker设置为Activated无效。~~
PS.UE大纲视图中的白色Actor是您自己放置在世界中的物品黄色Actor是您玩游戏时由引擎生成的物品。
***UE-173838 Actors in Level Sequence in a World Partitioned level do not move***
https://issues.unrealengine.com/issue/UE-173838
但5.2已经修复这个问题。
https://github.com/EpicGames/UnrealEngine/commit/51d38831de4da7df196eecaf13f3d4b5a517f1f0
## 最终结论
1. Sequence不能控制DMX是因为大世界存在垃圾需要使用上面的重新构建命令重新构建一下问题就解决了。
2. 舞台DMX可以考虑加一个Runtime DataLayer之后塞进LiveArea中。
1. 有关DataLayer的Runtime设置可以参考:https://youtu.be/LI6TsZf5hh0?si=nwqz-S6DDR7MgSBT
2. 这样可以保证看不到的Actor也会被加载。
3. 在异世界地图中也用到了WorldPartitionRuntimeStateVolumn。BP_LiveArea_12_1
4. AWorldPartitionRuntimeStateVolume是字节自己实现的。Puerts与C++没有任何调用,不知道该如何使用。
### ASoul的做法
1. 几个通用DataLayer
1. DL_AlwaysActive
2. DL_DMXStageAll
3. DL_EditorOnly
4. DL_LiveArea
2. 按照需要设置大世界专用DataLayer主要面对的是***占用区域较大,需要全部加载的。***
3. 通过TS脚本在进如LiveArea的时候通过DataLayerSubsystem来加载显示对应DataLayer
## 笔记
1. 枝江地图针对小房间、DMX、巨蛋DMX、舞蹈室以及舞台分别使用了DataLayer。
2. ***LvieArea***可以关联DataLayer并让其一起加载。比如乃琳卧室的LiveArea Map_SceneBedroom_Nailin以及BP_LiveArea_11关联了DL_SeasideCity_StageA。
- 加载
-  TsAreaListItemView.ts
- widget.IsLoad.OnCheckStateChanged.Add((bChecked)=>{this.OnLoadStateChanged(bChecked);});
- 加载manager.LayerManager.AddViewTarget(this.preset.LevelAreaPreset.AreaGuid, this.preset.LevelAreaPreset.Description);
- ***创建ADirectorReplicationViewTarget一个带有UWorldPartitionStreamingSourceComponent的Actor。*** 之后Attach到LiveArea上并且重合。
- class TsDirectorViewTarget extends UE.DirectorReplicationViewTarget。里面有一个定时器判断是否加载完加载完调用OnLoadComplete()(客户端加载逻辑。)
- ***在游戏状态下把TsDirectorViewTarget删除4级会显示没有加载这个场景。***
- ***TsLevelAreaManager.tsLoadAreaLayer()***
- 遍历LiveArea的CareLayers将LiveArea对应的DataLayer的状态设置为Actived。
- 销毁manager.LayerManager.RemoveViewTarget(this.preset.LevelAreaPreset.UUID);
- 切换
- TsAreaListItemView.ts SwitchLevel()
- TsMapEnvironmentLayerManagerEnterLevelArea()
TsMapEnvironmentAsset.ts读取JSON缓存所有的道具与资产路径之后异步加载。