地形及关卡流简单记录

前言

从遥远的2019年搬运而来, 仅作为记录,后续视情况补充

[官方文档][https://docs.unrealengine.com/zh-CN/Engine/Landscape/index.html]

地形的内存

  • 对于顶点数据,Landscape为每个顶点使用4个字节。静态网格体(Static Mesh)以12字节矢量的形式存储位置,每个切线X和Z矢量封装为4个字节,并为每个顶点的共24或28个字节存储16位或32位浮点UV。

  • 这意味着,对于相同的顶点密度,静态网格体(Static Mesh)将使用6或7倍于Landscape的内存。Landscape还将它们的数据存储为纹理,并且可以为遥远的区域流送未使用的LOD关卡,并在您接近它们时从后台的磁盘加载它们。Landscape使用一个常规的高度场,因此其碰撞数据也能够比静态网格体(Static Mesh)的碰撞数据更高效地存储。

地形存储方式

  • Landscape系统在GPU内存中以纹理的形式存储地形的渲染数据,允许在顶点着色器中查找数据。数据被打包成32位纹理,高度以R和G信道的形式占据16位X和Y偏移量以8位数值分别存储在B和A信道中

地形创建

属性 说明
SectionSize 用于设置地形 LOD 和消隐的分段尺寸。较小的尺寸使地形更积极地对分段设置 LOD,但 CPU 的消耗将增大。较大的尺寸即意味着组件较少,CPU 的消耗较小。创建大型地形时须使用较大的分段尺寸,因为在较小的分段尺寸下放大地形比例对 CPU 的消耗过大。
SectionPerComponent 此属性对地形 LOD 有辅助作用。每个分段都是地形 LOD 的基础单元。一个组件可能拥有 2 x 2 的分段,意味着一个组件一次可渲染四个不同的 LOD使用较大的分段尺寸可减少 CPU 计算时间,从而获得额外的益处。然而,地形同时渲染数量过多的顶点时可能出现问题。使用超大的地形区域时问题将普遍存在。这些问题在移动设备上可能尤为严重,因为绘制调用的数量将受到硬件限制。
Numbers of Components 和 section size 一同用于地形尺寸的设置。此数值的上限为 32 x 32,因为每个组件均会产生 CPU 消耗;超过此上限可能引起地形的性能问题。
OverallResolution 顶点数
TotalComponents 组件数,CPU消耗主要决定因素
  • 以下是简单理解
  • Component:地形基本单元,一个Component会被整体裁剪或者渲染以及处理碰撞
  • Section:Lod基本单元
  • Quad:网格数量,或者说顶点数

地形碰撞

CollisionMipLevel

处理复杂碰撞精细度,越高越不精确

SimpleCollisionMipLevel

简单碰撞的处理精细度,越高越不精确

01

02

  • 上图是用playerCollision模式查看简单碰撞模式,分别是0,3的显示结果
  • 用VisibilityCollision模式查看复杂碰撞的结果类似
  • 同理可以对不同地形component的碰撞精细度进行处理

关卡流

目前提供两种加载方式

  • 蓝图或者c++手动加载
  • LevelStreamingVolume盒子自动加载

蓝图加载

image-20191211152428687

C++加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
UGameplayStatics::LoadStreamLevel(GEngine->GetWorld(), LevelName, 1, 0, FLatentActionInfo{});

//函数定义
void UGameplayStatics::LoadStreamLevel(const UObject* WorldContextObject, FName LevelName,bool bMakeVisibleAfterLoad,bool bShouldBlockOnLoad,FLatentActionInfo LatentInfo)
{
if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull))
{
FLatentActionManager& LatentManager = World->GetLatentActionManager();
if (LatentManager.FindExistingAction<FStreamLevelAction>(LatentInfo.CallbackTarget, LatentInfo.UUID) == nullptr)
{
FStreamLevelAction* NewAction = new FStreamLevelAction(true, LevelName, bMakeVisibleAfterLoad, bShouldBlockOnLoad, LatentInfo, World);
LatentManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, NewAction);
}
}
}

LevelStreamingVolume

image-20191211152559630

  • 如上图,在关卡细节里面需要指定子关卡对应的盒子(绑定)
  • 多个盒子可以一起作用

  • 两者不能同时作用,必须把盒子disable后才可以用方法去控制