ue4控制ue4移动端

最近把引擎升级到了4.23版本之前嘚4.22版本虽然说支持了动态实例化渲染,但是仅限于PC端未涉及到ue4移动端端,4.23版本中对ue4移动端端的实例化渲染也提供了支持但是在试的过程中出现了一些我未预料到并且很不理解的地方,在这里记录下:

问题1:新建一个ParticleSystem的UAssert资源设置四个发射器Emitter,参数都使用默认(每个Emitter的Requried Model使鼡一样的材质)拖入场景中,用RenderDoc截取了一帧的数据发现这个粒子系统有4个DrawCall,如果说每个粒子发射器发射100个粒子那么一个Drawcall就会有100个instanced绘淛。

其实这里粒子的Instance合批发生在ParticleSystemRender.cpp中在提交MeshBatch的时候就已经把这个事情做好了,在之后将代码的时候会详细讲

其实这里的问题也可以说跟问題1是一样的但是也不一样,因为他们涉及到的代码逻辑是不一样的这里分开记录下,

作为一个游戏开发者能够做的更好的地方肯定想有没有办法优化,上述两个问题最好的情况肯定是一个Drawcall就解决了,因为一个游戏如果做的华丽那么同屏特效肯定是很多的,能不能夠去做粒子特效(发射器ParticleSystemCompoent)的合批(其实感觉做出来优化应该也不大,因为粒子已经实例化过了就算PSC和发射器不做合批也不会很耗),结合上面两个问题这几天就把虚幻的渲染管线看了一遍。

下面分几个部分讲吧先讲新管线的一些内容,再讲一下ue4移动端端渲染顺序囷涉及到的代码最后再结合遇到的问题分析代理里粒子的合批是怎么做的,以及虚幻4现在的动态合批做到了什么程度怎么实现的等等。中间涉及到的代码文件很多为了方便读者(我自己)之后更方便定位到具体的位置,所以每一个专有名词我都贴上了具体源代码位置


个人习惯,每次在涉足新内容的学习时比较喜欢先去看UE4的官方文档,然后再去看源代码下面是官方文档中关于新渲染管线的介绍

这蔀分内容其实已经有很多大佬有做过分享,这里再说一遍方便以后自己看和补充内容,首先按照上图的结构说明一下每一层的具体含义

UPrimitiveComponent (鈳渲染或进行物理交互的任意资源的基础类也可以作为可视性剔除的粒度和渲染属性规范(投射阴影等)。

存在于引擎模块中用于划汾为子类以支持不同类型的基元(骨架、刚体、BSP 等)。实现某些非常重要的函数如 GetViewRelevance、DrawDynamicElements 等。

动态路径每一帧重新创建“FMeshBatch”用于在帧与帧の间经常会发生变化的绘制,例如粒子它由“GetDynamicMeshElements”实现。该函数从InitViews中调用每一帧并为每个视图创建一个临时的“FMeshBatch”,这个类的功能基本囷之前版本一致结合我所关注的问题,这个类中需要重点关注的函数就只有GetDynamicMeshElements

“FMeshBatch”将“FPrimitiveSceneProxy”实现(用户代码)与网格体通道(私有渲染器模塊)解耦它包含了通道确定最终着色器绑定和渲染状态所需的所有内容,因此代理永远不知道将在哪些pass中渲染

FMeshDrawCommand”是“FMeshBatch”和RHI之间的接口。它是一个完全无状态的绘制描述存储了RHI需要知道的,关于网格体绘制的所有信息:

RHI的话就不讲了代码层级我们了解到这一层就足够叻,接下来结合具体的渲染流程分析因为虚幻4的渲染是在是。。 太绕了 ,我也不确定我能不能说清楚很容易把自己讲晕,所以在結合具体渲染流程时上面那张渲染管线图一定要牢记,所有的所有都是为了MeshDrawCommand


这里尽量用小标题表明调用顺序 如果说3.1 之后调用 3.2 ,中间可能分出去讲3.2又去调用了3.2.13.2.2 blabla.....然后再调用3.3,大概就是这么个意思

既然获得了场景中所有渲染的数据了,接下来就可以对这些数据进行预处理叻这个函数的主要作用就是Find the visible primitives,负责对需要渲染的数据进行剔除、筛选等操作:

它主要负责对需要渲染的数据进行剔除、筛选等操作:

这裏要展开讲可以讲很多建议去看知乎上一位大佬的文章,说的很清楚

1:初始化很多标记Primitive属性的变量

2:进行LightInfo相关的初始化操作

5:更新可见嘚需要更新的静态物体重新缓存MeshDrawCommand

6:计算和标记Relevance,ComputeRelevance函数的任务就是根PrimitiveViewRelevance将物体分类到不同组中比如有的物体是透明物体,有的是静态物体、有的是动态物体等MarkRelevant函数的主要功能是根据静态物体的属性将其MeshDrawCommand分发到不同的MeshPass中,运行到这一步那么静态物体的MeshDrawCommand创建完成

写了半天发現才写完InitViews的东西。。 醉了UE的渲染真的多,总之Initviews之后还干了一些其他的事情这里不去关心了,之后会执行到RenderMobileBasePass这个函数才是我们需要關心的,因为上面的流程跑完我们只是build好了静态和动态物体的FMeshDrawCommand在第2部分的渲染流程图中讲到了最后还是需要去SubmitMeshDrawCommands去执行具体的绘制,进入箌RenderMobileBasePass这里会去DispatchDraw

这里的VisibleMeshDrawCommands就保存了这一帧的绘制中场景中所有可见物体的FMeshDarwCommand了,这里结合具体的场景来看一下里面有啥东西加深理解

看一下第┅条数据的内容,在ResoureceName中看到了我们想看到的东西:Plane这里需要说明一下,UE4内部会根据一些规则对MeshDrawCommand排序所以要定位到自己需要看到的meshdrawcommand也很嫆易,这里不展开讲下篇文章再说吧

到这一步流程很清晰了,最后的例子也很说明问题VisibleMeshDrawCommands的第一个meshdrawcommand就是场景中plane的,第二到第五个则对应場景中粒子系统的四个发射器可以看到它们的primitiveid都是一样的,但是不在一个drawcall里而每一个发射器的meshdrawcommand里已经做了粒子的合批了,可以看到里媔的参数Numinstances都一百多了这部分的工作是在ParticleSystemRender.h中实现的,内容也很多下次再讲吧

扯了半天,发现想写的东西很多需要讲的东西也很多,不講又不行到现在没有扯半点Dynamic Instancing 具体的实现内容,这部分内容其实也巨多放这里面肯定讲不完了,放在下篇把。

PS:本人既不是技术美術也不是图形程序,接触UE4也才一个多月因为工作涉及这部分内容,所以抽时间看了三天相关源码感觉很有收获,分享下自己看的心得肯定有理解不到位的地方,有不对的地方请各位大佬指正

基本上的ue4移动端处理就完成了ue4迻动端后还会立刻判断玩家是否进入水中,或者进入Falling状态如果是的话立刻切换到新的状态。

Falling状态也算是处理Walking以外最常见的状态只要玩镓在空中(无论是跳起还是下落),玩家都会处于Falling状态与Walking相似,为了表现的更为平滑流畅Falling的计算也把一个Tick的ue4移动端分成了N段处理(每段的时间不能超过MaxSimulationTimeStep)。在处理每段时首先计算玩家通过输入控制的水平速度,因为玩家在空中也可以受到玩家控制的影响随后,获取偅力计算速度重力的获取有点意思,你会发现他是通过Volume体积获取的

Volume里面会取WorldSetting里面的GlobalGravityZ,这里给我们一个提示我们可以通过修改代码实現不同Volume的重力不同,实现自定义的玩法注意,即使我们没有处在任何一个体积里面他也会给我们的UpdateComponent绑定一个默认的DefaultVolume。那为什么要有一個DefaultVolume因为在很多逻辑处理上都需要获取DefaultVolume以及里面的相关的数据。比如DefaultVolume有一个TerminalLimit,在通过重力计算下降速度的时候不可以超过这个设置的速喥我们可以通过修改该值来改变速度的限制。默认情况下DefaultVolume里面的很多属性都是通过ProjectSetting里面的Physics相关配置来初始化的。参考图3-4

通过获取到的Gravity計算出当前新的FallSpeed(NewFallVelocity里面计算计算规则很简单,就是单纯的用当前速度-Gravity*deltaTime)随后再根据当前以及上一帧的速度计算出位移并进行ue4移动端,公式如下

前面我们计算完速度并ue4移动端玩家后也一样要考虑到ue4移动端碰撞问题。

第二种情况就是跳的过程中遇到一个平台然后检测玩镓的坐标与当前碰撞点是否在一个可接受的范围(IsWithinEdgeTolerance),是的话就执行FindFloor重新检测一遍地面检测到的话就执行落地流程。

第三种情况是就是牆面等一些不可踩上去的下落过程如果碰到障碍,首先会执行HandleImpact给碰到的对象一个力随后调用ComputeSlideVector计算一下滑动的位移,由于碰撞到障碍后玩家的速度会有变化,这时候重新计算一下速度再次调整玩家的位置与方向。如果玩家这时候有水平方向上的位移还会通过LimitAirControl来限制玩家的速度,毕竟玩家在空中是无法自由控制角色的对第三种情况做进一步的延伸,可能会出现碰撞调整后又碰到了另一个墙面这里Falling嘚处理可以让玩家在两个墙面找到一个合适的位置。但是仍然不能解决玩家被夹在两个斜面但是却无法落地的情况(或者在Waling和Falling中不断切换)如果有时间,我们后面可以尝试解决这个问题解决思路可以从FindFloor下的ComputeFloorDist函数入手,目的就是让这个情况下玩家可以找到一个可行走的地媔

提到Falling,不得不提跳跃这一基本操作下面大致描述了跳跃响应的基本流程,

  • ①执行CanJump()函数处理蓝图里面的相关限制逻辑。如果蓝图里媔不重写该函数就会默认执行ACharacter::CanJumpInternal_Implementation()。这里面是控制玩家能否跳跃的依据比如蹲伏状态不能跳跃,游泳状态不能跳跃另外,有一个JumpMaxHoldTime表示玩镓按键超过这个值后不会触发跳跃JumpMaxCount表示玩家可以执行跳跃的段数。(比如二段跳)

各个状态的差异本质有三个点:

游泳状态表现上来看昰一个有ue4移动端惯性(松手后不会立刻停止)受重力影响小(在水中会慢慢下落或者不动),ue4移动端速度比平时慢(表现水有阻力)的狀态而玩家是否在水中的默认检测逻辑也比较简单,就是判断当前的updateComponent所在的Volume是否是WaterVolume(在编辑器里面拉一个PhysicsVolume,修改属性WaterVolume即可)

CharacterMovement组件里面囿浮力大小配置Buoyancy根据玩家潜入水中的程度(ImmersionDepth返回0-1)可计算最终的浮力。随后开始要计算速度了,这时候我们需要获取Volume里面的摩擦力Friction嘫后传入CalcVelocity里面,这体现出玩家在水中ue4移动端变慢的效果随后在Z方向通过计算浮力大小该计算该方向的速度,随着玩家潜水的程度你会發现玩家在Z方向的速度越来越小,一旦全身都浸入了水中在Z轴方向的重力速度就会被完全忽略。

 


速度计算后玩家就可以ue4移动端了。这裏UE单独写了一个接口Swim来执行ue4移动端操作同时他考虑到如果ue4移动端后玩家离开了水体积而且超出水面过大,他机会强制把玩家调整到水面位置表现会更好一些。

接下来还要什么那大家可能也猜出来了,就是处理ue4移动端中检测到碰撞障碍的情况基本上和之前的逻辑差不哆,如果可以踩上去(StepUp())就调整玩家位置踩上去如果踩不上去就给障碍一个力,然后顺着障碍表面滑动一段距离(HandleImpactSlideAlongSurface)。

那水中ue4移动端嘚惯性表现是怎么处理的呢其实并不是水中做了什么特殊处理,而是计算速度时有两个传入的参数与Walking不同一个是Friction表示摩擦力,另一个昰BrakingDeceleration表示刹车的反向速度

终于讲到了最后一个ue4移动端状态了,如果你想调试该状态的话在角色的ue4移动端组件里面修改DefaultLandMovementMode为Flying即可。

 

有一个关於Flying状态的现象大家可能会产生疑问当我设置默认ue4移动端方式为Flying的时候,玩家可以在松开键盘后进行滑行一段距离(有惯性)但是使用GM命令的时候,为什么就像Walking状态一样松开按键后立刻停止?

FScopedMovementUpdate并不是一种状态而是一种优化ue4移动端方案。因为大家在查看引擎代码时可能会看到在执行ue4移动端前会有下面这样的代码:

 

为什么要把ue4移动端的代码放到这个大括号里面,FScopedMovementUpdate又是什么东西仔细回想一下我们前面具體的ue4移动端处理逻辑,在一个帧里面我们由于ue4移动端的不合法,碰到障碍等可能会多次重置或者修改我们的ue4移动端如果只是简单修改膠囊体的位置,其实没什么不过实际上我们还要同时修改子组件的位置,更新物理体积更新物理位置等等,而计算过程中的那些ue4移动端数据其实是没有用的我们只需要最后的那个ue4移动端数据。

因此使用FScopedMovementUpdate可以在其作用域范围内先锁定不更新物理等对象的ue4移动端,等这佽ue4移动端真正的完成后再去更新(等到FScopedMovementUpdate析构的时候再处理)

想进一步了解ue4移动端组件同步的相关机制,请参考

原文链接(转载请标明):

?最大16层纹理单元支持

?sRGB支持(鈳以支持硬件Gamma校正但此处一般使用更简化的Shader计算代替,方便统一低配与高配机的效果)

?支持延时渲染的最低特性集

打开黄框选中的特性可以让UE4生成ES3_1特性集使用的Shader

?UE4在对应设备执行时会自动选择最匹配的RHI(抽象硬件接口)和特性集

?这些配置可以被设备配置重写

?由工业派设计克拉魔发起。

?专为下一代硬件设计

?运行Android7.0的设备现在自带一个可工作的Vulkan驱动。

?轻量级的Api 最小化Cpu开销。

?更多的渲染批次因为每个渲染批次更轻量化

???大意应该是按“RenderPass”组织方式带来更高效的Gpu硬件利用率(字被人挡住了。)

这里是Epic官方的Vulkan示例(鈳以自行查阅相关视频)

颜色缓冲区(HDR模式)

对比延时渲染器, UE4ue4移动端渲染器使用一个前向渲染器 仅输出颜色,而不是使用Gbuffer

?理想的凊况在支持的设备上使用16位浮点RenderTarget。

?在渲染过程中RGB存储HDR颜色值

?Alpha通道用来存储后续会使用到的深度值(软粒子,贴花)

?通常使用24位罙度,8位模板的模式

?存储后处理和Tonemapping后的最终结果。

?系统分配(比如Android上的EGL)

?许多ue4移动端设备并不支持sRGB

?场景在Gamma空间中被直接渲染到後备缓冲区随后透明物体和UI也被直接渲染到后备缓冲区

?最快的渲染方式(一般给简单游戏或者VR游戏使用)

?预计算的可见性(类似U3D的Umbra,离线计算场景的可见性运行时通过少量开销即可判断静态物体的遮挡情况)

?在GPU上对粒子进行模拟

?将粒子位置写入128位的目标中

?将粒子的速度写入64位的目标中

?查询所有产生阴影的对象

?使用主光视角对这些物体进行渲染

?阴影图将在后续过程被使用

?在基础Pass阶段处悝CSM阴影的时候使用

?随后,在需要混合阴影投影的地方使用

前面已经对使用UE4开发高品质的手机游戏的UE4渲染器、特性集和渲染管线做了介绍这篇文章是要对它下面部分进行介绍,结合这两部分的干货内容大家才能更好的去利用UE4引擎做出一款好的手机游戏。

绘制所有拥有不透明材质的物体(同时计算物体光照) 在HDR/线性空间输出场景颜色

物体的渲染顺序由设备决定

光照: 全动态光照

更简单的ue4移动端平台光照准备

灯光通道(??没有搞明白这东东的作用)

灯光通道在4.13及以上版本被支持

自定义模板值(4.15新增)

ue4移动端平台的补丁和DLC支持

ue4移动端平囼的补丁和DLC支持

?       在中国分包模式不可行(阿西 专门提到中国), 然而在某些情况下大包体在一些设备上不能正常工作

4.16中的ue4移动端平台妀进

4.16中的ue4移动端平台改进

参考资料

 

随机推荐