【UE】大世界子关卡StreamingLevel加载流程源码浅析-虚幻4

这篇具有很好参考价值的文章主要介绍了【UE】大世界子关卡StreamingLevel加载流程源码浅析-虚幻4。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

受限于硬件,当项目需要制作大世界的时候,整张大地图无法也没必要全部加载进内存。和所有支持大世界的引擎一样,UE采取了分块加载的方式:除了一个持久关卡(PersistentLevel)的加载以外,采用的都是运行时动态加载的方式,我们称这些关卡为子关卡或者流关卡(StreamingLevel)。当玩家到达子关卡边界的时候它们才开始加载。

本文基于UE4.27,简述流关卡加载的流程和时机。除非解释原理必要,不会涉及如何使用。具体使用方式可以参考:YakSue的《学习UE4的WorldComposition基础》

虚幻4中的子关卡编辑

先来直观体验一下子关卡的编辑界面

Window-》Level打开“关卡”选项卡
ue4加载关卡,UE4学习手册,游戏引擎,ue4,游戏引擎,游戏程序,c++
我这里新建了三个关卡作为子关卡。可以看到除了默认的level作为持久关卡以外,其它的关卡都属于子关卡。游戏刚开始不会加载到内存,而是根据玩家位置和关卡距离,在运行时进行动态加载

单击调出世界场景构成。
ue4加载关卡,UE4学习手册,游戏引擎,ue4,游戏引擎,游戏程序,c++

世界场景构成中可以看到一个默认layer:“Uncategorized”,这里我新建了一个layer叫“我的图层”
ue4加载关卡,UE4学习手册,游戏引擎,ue4,游戏引擎,游戏程序,c++
简单解释一下layer的概念:可以看到在编辑器中编辑子关卡的时候,每个子关卡都属于一个layer,layer可以设置流送距离,这个距离是判断关卡可见性的一个重要属性,我们后文会提到

如果想让关卡距离玩家近一些才加载,就新建一个layer,把目标关卡放入新layer并调小新layer的流送距离即可

流关卡加载涉及到的类

一个大世界(World)由多个关卡(Level)组成,其中与流关卡加载有关的关键类及其属性如下:
ue4加载关卡,UE4学习手册,游戏引擎,ue4,游戏引擎,游戏程序,c++
ULevelStreaming:存放与流关卡加载相关的标记和方法,如当前状态(加载中、已加载、加载但不可见、加载且可见…)、目标状态等。

UWorld:StreamingLevelsToConsider存放当前待加载的流关卡,StreamingLevels存放已经加载的流关卡。属于运行时动态更新的两个容器

UWorldComposition:加载流关卡的主要负责类,其中Tiles存放其所属World的子关卡Summary信息,是流关卡加载的最小单位;TilesStreaming存放其当前状态。两个TArray通过下标一一对应。这两个数据结构基本只在开始的时候初始化一次,存储所属World下所有的流关卡信息。

UWorldComposition的Tiles可以看作是一个TArray<FWorldCompisitionTile>,其关键属性如下:

// WorldComposition.h
// Helper structure which holds information about level package which participates in world composition
struct FWorldCompositionTile
{
	FName	PackageName;
	FWorldTileInfo	Info;
}

而FWorldTileInfo包括这个Tile的位置(Position)、绝对位置(AbsolutePosition)、边界(Bounds)和ZOrder等信息

加载流程

加载流程分为三个部分:

  1. 收集关卡资源
  2. 根据玩家位置标记流关卡状态
  3. 执行关卡的加载or卸载
    ue4加载关卡,UE4学习手册,游戏引擎,ue4,游戏引擎,游戏程序,c++

收集流关卡资源

在UWorldComposition构造即将完成的时候,会调用UWorldComposition::Rescan进行流关卡资源的收集。这个函数会查找当前World的根目录,将其中流关卡的Summary信息反序列化到内存。
ue4加载关卡,UE4学习手册,游戏引擎,ue4,游戏引擎,游戏程序,c++
注意这里只是反序列化了各个关卡的一点必要信息如关卡位置,给后续判断关卡什么时候应该加载用。并没有把整个流关卡都反序列化进来。

收集完信息到Tiles这个结构体以后,调用UWorldComposition::PopulateStreamingLevels给每个流关卡都赋上初始状态。

这一步的结果就是完成了流关卡信息的收集,具体到结构体就是Tiles和TilesStreaming的初始化。

这一步骤基本只在构造即将结束的时候执行一次。接下来的两个步骤是在游戏进行中反复执行的。

根据玩家位置计算Tiles的可见性

UWorld::Tick()会调用到UWorldComposition::UpdateStreamingState 这里根据一些必须加载的位置如玩家当前位置、PersistentLevel的位置计算应该加载、卸载的关卡。
ue4加载关卡,UE4学习手册,游戏引擎,ue4,游戏引擎,游戏程序,c++
这一步也只是做了关卡状态的计算,标记了关卡的TargetState,并将待加载的关卡放入UWorld的StreamingLevelsToConsider容器中。并没有真正加载关卡

关卡可见性计算方式
源码注释中写道:
Check if tile bounding box intersects with a sphere with origin at provided location and with radius equal to tile layer distance settings

即判断 关卡(Tile) 的bounding box与指定位置为圆心的球体是否相交,这里球体的半径是这个 关卡(Tile) 所在layer设置好的流送距离

关键部分源码如下:

void UWorldComposition::GetDistanceVisibleLevels(
	const FVector* InLocations,
	int32 NumLocations,
	TArray<FDistanceVisibleLevel>& OutVisibleLevels,
	TArray<FDistanceVisibleLevel>& OutHiddenLevels) const
{
	……
	for (int32 TileIdx = 0; TileIdx < Tiles.Num(); TileIdx++)
	{
		……
		for (int32 LocationIdx = 0; LocationIdx < NumLocations; ++LocationIdx)
		{
			FSphere QuerySphere(InLocations[LocationIdx], TileStreamingDistance);
			if (FMath::SphereAABBIntersection(QuerySphere, LevelBounds))
			{
				VisibleLevel.LODIndex = LODIdx;
				bIsVisible = true;
				break;
			}
		}
	}
}

函数传入一些关键点位置InLocations,如玩家位置。

FSphere QuerySphere(InLocations[LocationIdx], TileStreamingDistance):以关键点InLocations[LocationIdx]为球心、TileStreamingDistance为半径构造一个球体,判断这个球与关卡边界是否相交。如果相交则认为该关卡距离玩家已经很近了,需要载入内存中。

执行流关卡加载

终于到了真正加载的地方了。客户端绘制到屏幕的时候 根据上一步收集来的StreamingLevelsToConsider进行关卡的载入内存和显示。
ue4加载关卡,UE4学习手册,游戏引擎,ue4,游戏引擎,游戏程序,c++实际的加载在ULevelStreaming::RequestLevel中进行:

bool ULevelStreaming::RequestLevel(UWorld* PersistentWorld, bool bAllowLevelLoadRequests, EReqLevelBlock BlockPolicy)
{
	... ...
	const FName DesiredPackageName = bIsGameWorld ? GetLODPackageName() : GetWorldAssetPackageFName();
	if (bAllowLevelLoadRequests)
	{
		const FName DesiredPackageNameToLoad = bIsGameWorld ? GetLODPackageNameToLoad() : PackageNameToLoad;
		const FString PackageNameToLoadFrom = DesiredPackageNameToLoad != NAME_None ? DesiredPackageNameToLoad.ToString() : DesiredPackageName.ToString();
		if (FPackageName::DoesPackageExist(PackageNameToLoadFrom))
		{
		... ...
			LoadPackageAsync(DesiredPackageName.ToString(), nullptr, *PackageNameToLoadFrom, FLoadPackageAsyncDelegate::CreateUObject(this, &ULevelStreaming::AsyncLevelLoadComplete), PackageFlags, PIEInstanceID, GetPriority());
		... ...
	}
	... ...
}

应用:屏蔽部分子关卡的加载

如果本地有子关卡资源,但运行时不希望加载,需要进行子关卡的屏蔽。在UWorldComposition::Rescan收集的时候对指定关卡进行屏蔽即可。

注意由于子关卡的信息收集和加载是在Server和Client各自进行的,并不是通过网络同步从Server下发到Client。如果要做屏蔽操作也是服务器和客户端都需要执行的。

否则会出现服务器屏蔽了地表但客户端仍会显示,而由于碰撞的裁决在服务器,这块地表会没有碰撞:文章来源地址https://www.toymoban.com/news/detail-649867.html

到了这里,关于【UE】大世界子关卡StreamingLevel加载流程源码浅析-虚幻4的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • AI最新进展介绍——大世界模型Large World Model (LWM)

    UC Berkeley    大世界模型( LWM )是一种通用的大型上下文多模态自回归模型。它使用 RingAttention 在一个包含各种长视频和书籍的大型数据集上进行训练,可以进行语言、图像和视频的理解和生成。   目前的语言模型在理解“世界上难以用言语描述的方面”存在不足,而且

    2024年03月10日
    浏览(61)
  • 制作unity大世界场景编辑的一点心得和注意事项(场景地编)

    制作unity大世界场景的一点心得和注意事项(地编注意事项) 这是一个项目的整个注意事项,所注意点都是根据制作的项目整理的。所以在做任何项目的时候要注意 举一反三 。 1,检查分组里的各种检查(这里的分组是每一个场景尤其是大世界地图制作人员比较多需要合理规

    2024年02月07日
    浏览(59)
  • 城市建筑模型UE虚幻引擎加载处理流程

    目前,建筑轮廓矢量数据的获取方式有多种: (1)osm开源数据下载。 (2)地形图转绘。 (3)其他如立体测绘等方式提取。 使用cityengine导入建筑矢量数据,根据楼层信息建立建筑立体轮廓。 根据自带的开放纹理库进行建筑纹理贴图,纹理库有多重风格提供选择。 建筑模型导出ob

    2024年02月05日
    浏览(39)
  • Ue4创建新关卡,场景一片漆黑怎么解决?

    首先遇到这个问题是因为新创建的关卡内什么也没有,所以需要在场景中添加天空系统和光源。 需要在场景中添加几个东西分别是:定向光源,BP_Sky-Sphere,天空光照。 (大气雾) 定向光源和天空光照需要将坐标初始化。

    2024年02月13日
    浏览(42)
  • 解决UE4 UE5 虚幻引擎 关卡内或sequence 播放多个视频卡顿问题

    在项目设置中搜索缓存,修改其中的参数即可解决问题,默认为1G,详细见图 经测试,单个关卡内使用蓝图或在sequence内创建媒体,播放30个mp4视频或者序列帧分辨率为1080p,可流畅播放,实时帧数40fps,使用设备(2080ti,内存64G)

    2024年02月11日
    浏览(74)
  • UE5热更新:Pak包的Cook、打包、加载全流程及踩坑经验分享

    探索UE5中Pak包加载的全流程,包括Cook、打包、加载等步骤,并分享在实践中遇到的一些坑和解决方法。跟随本教程,了解UE5与UE4的不同之处,以及如何成功实现热更新功能。

    2024年02月03日
    浏览(68)
  • UE4使用GameInstance设置全局变量(不同关卡、类之间数据传递)

    一、GameInstance是什么? (UE4官方)是一个正在运行的游戏的 高级别的管理对象 ,在游戏创建时生成,游戏实例关闭时销毁,一个游戏中可以有多个GameInstance; 在游戏中切换关卡,GameInstance不会销毁(切换关卡时可用GameInstance携带信息); 二、GameInstance有什么作用? 在多关

    2024年02月02日
    浏览(72)
  • UE4-UMG点击播放关卡序列(Level Sequence)

    1.在UE4关卡蓝图中播放关卡序列步骤 (1)把创建好的关卡序列拖入场景中 (2)选中需要播放的关卡序列,在关卡蓝图中添加引用 (3)添加play节点 运行时就能轻松播放关卡序列了 2.在UMG中点击按钮播放关卡序列有两种方法 方法一: (1)添加创建关卡序列播放器,选择需要

    2023年04月15日
    浏览(45)
  • 【保姆级从0到1】UE5 蓝图入门教程1:关卡、蓝图入门

    20230113 新建选择 UE 5.1 项目 选择蓝图,项目位置 改变编辑器布局,选择经典布局 选择 File - New Level 准备创建关卡 选择 Basic,点击 Create 进行创建 Ctrl + S 保存新建的关卡 关卡蓝图的打开 鼠标右键,添加蓝图事件,这里先删除默认的所有蓝图,然后鼠标右键,选择 事件开始运

    2023年04月08日
    浏览(41)
  • 如何使用UE5新功能 “打包型关卡Actor” 实现场景的性能优化

    内容分为: 简介 实操 优化结果展示 看不懂原理看看实操就大概就能明白 “打包型关卡蓝图”是UE5新功能 世界分区(World Partition) 的一部分 但 不依赖于项目是否启用了世界分区 官方文档有关世界分区中 关卡实例化 的内容 官方文档: 这个功能的原理是将场景中的 静态网

    2024年02月12日
    浏览(108)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包