立即注册
登录
搜索
前端开发
后端开发
虚幻引擎
U3D引擎
体感研发
数据库
论坛
BBS
本版
帖子
用户
麒麟软控
»
论坛
›
麒麟软控
›
虚幻引擎
›
虚幻引擎UE渲染框架
返回列表
发新帖
虚幻引擎UE渲染框架
韶华易逝
韶华易逝
当前离线
积分
13
4
主题
5
帖子
13
积分
新手上路
新手上路, 积分 13, 距离下一级还需 37 积分
新手上路, 积分 13, 距离下一级还需 37 积分
积分
13
发消息
发表于 2022-9-20 09:41:35
|
显示全部楼层
本文整体介绍虚幻引擎UE的渲染框架。
以通俗易懂的方式描述,不喜欢上代码,个人风格就是能用文字和图片介绍清楚就不上代码,希望对新手友好、对代码犯困者友好。也不喜欢把文章写的太长,万字长文自己看着都犯困,尽量精简。
此外,读者最好有基本的图形学基础。当然没有也没关系,遇到陌生名称如延时渲染、pass百度了解下就行。
目录
渲染引擎流程
UE多线程渲染
UE渲染流程架构
渲染依赖图
总结
渲染引擎流程
开始介绍渲染架构之前,先了解下整个渲染引擎需要做的事情。
简单来说,渲染就是将一个虚拟场景,以摄像机视角,渲染出屏幕图像的过程。如图1。
图1 渲染展示
虚拟场景
一般是以某数学形式表示的三维表面。
虚拟摄像机
为场景取景。
光源
产生的光线会与环境中的物体交互作用并反射,到达虚拟摄像机从而产生画面。 渲染结果如图中右下角。
对于引擎来说,要完成整个过程,大致需要经历以下步骤。
图2 渲染引擎流程
资源加载:加载本地模型、材质等资源
场景搭建:将场景中的物体以特定的数据结构组织起来
视锥裁剪:剔除掉不在当前视角范围内的物体
可见性判定:剔除当前视角下被遮挡的物体
渲染管线:描述如何渲染、设置渲染状态、分配GPU资源
渲染指令:生成GPU执行的指令
GPU:真正开始渲染
多线程渲染
谈到UE渲染框架,不得不从多线程开始。当然,这里不会谈论UE的所有线程模块,也不会谈及线程的线程池、线程管理、任务图等。
这里只讨论与渲染最相关的三个线程:游戏线程、渲染线程、RHI线程。
游戏线程:也叫引擎线程、主线程,核心线程,负责整个引擎以及游戏的逻辑、运行。
渲染线程:渲染的流程的主要线程,负责整个渲染资源收集、状态设置、生成渲染指令等。
RHI线程:(Render Hardware Interface)线程将渲染指令转成指定图形API,并提交给GPU。
图3 线程关系
三个线程的关系如图。将三个线程整合到图2中,对应的流程如下。
图4 线程功能划分
其中游戏线程负责资源加载合场景搭建,渲染线程负责剔除、渲染管线,RHI负责生成指令提交GPU渲染。
三个线程都是在LaunchEngineLoop.cpp的PreInitPostStartupScreen中创建、开启。这个接口有1500+行,还只是预初始化相关操作,感兴趣的读者可以自行阅读。
图5 引擎接口
线程通信
基于分层式的设计,不同层级完成不同任务,需要做到相互独立、低耦合,虚幻采样的是命令方式。不同层级之间通过指令交互,如图6。
图6 通信流程
数据更新
多线程存在一个棘手的问题就是
数据竞争
。发生数据竞争时可能导致不可预期的结果,甚至使程序崩溃,而且这种BUG通常是偶现的,很难排查。
UE对数据竞争的解决方案就是
一对一服务
。不同线程拥有单独数据,每份数据明确修改者和修改对象,同一线程使用固定的数据。
那么,这必然存在一个问题:不同线程要使用同一份数据怎么办?比如,游戏线程和渲染线程都需要使用场景中的物体网格等。
答案就是
复制
!每个线程拥有一份!这样达到数据隔离的目的。当然,这种方式针对的是动态数据,如骨骼网格。静态资源只需要一份,保证所有线程都使用完才释放即可。
因此,不同线程中出现了一些不同名字,但是代表同一事物的命名。如下
图7 命名对应关系
再回过头看UE的多线程渲染机制,事实上,多线程并非多个渲染线程,渲染线程从始至终只有一个。这里的多线程指的是游戏线程、渲染线程、RHI线程同时存在,并行处理整个渲染过程。每个线程负责不同的任务而已。
此外,三个线程的处理速度并不一致,如图8,渲染线程在游戏线程的一两帧后操作。如果游戏线程跑的太快,游戏线程会在每个Tick事件的末尾阻塞,直到渲染线程赶上一到两帧的差距,才继续处理下一帧。
图8 不同线程处理速度
渲染流程架构
正式进入渲染管线核心部分的介绍。UE的渲染管线的大框架采用的是延时渲染管线,但又不是纯粹的延时渲染管线,参杂了一些其他的逻辑,如前向渲染、全局光照、LPV等等。
图9 整体架构图
UE渲染整体架构如图9。每个view是一趟独立渲染流水线。整体流程相对简单。
首先针对一个场景,找出所有需要渲染的view,经过模型网格绑定、剔除、等系列处理。随后将view拆分为多个pass进行渲染。
整体的代码在FDeferredShadingSceneRenderer::Render中。整个接口1400+行,感兴趣的可自行阅读。
图10 渲染接口代码
真正复杂的是过程的具体实现。下面将详细介绍整个过程。
图11 渲染过程详解
发起渲染:
游戏线程在Tick时,会创
建场景渲染器
,并向渲染线程发送绘制场景指令,会进入渲染模块的调用
更新图元信息:
通过UpdateAllPrimitiveSceneInfos接口,更新所有图元的信息并同步到GPU
初始化准备工作:
初始化View尺寸 、分配渲染纹理
初始化View
:初始化View中包含计算可见性和收集图元信息
首先需要取拿到所有需要渲染的网格
静态网格收集
在PreVisibilityFrameSetup接口中
动态网格收集
在ComputeViewVisibility中
除了收集动态网格,该接口还负责视锥裁剪、遮挡剔除
各Pass渲染
Pre-Pass:提前深度测试,渲染不透明物体的深度
BasePass:延迟渲染的几何pass,渲染不透明物体的几何信息
Lighting Pass:光照pass,非常复杂的一趟pass,包含各种光源的间接阴影、天空光、AO、透明体积光照等等
Translucency:渲染半透明物体
PostProcessing:后处理阶段,渲染各种屏幕效果
渲染依赖图
最后再介绍下基于渲染依赖图RDG的渲染优化。
概念
可以看到渲染代码中随处可见的GraphBuilder
图12 接口
图13 接口
图14 接口
GraphBuilder
即是依赖性渲染图(RDG),用于渲染管线的整帧优化,减少渲染指令的数量。
RDG最初是2017年的GDC中,寒霜实现并应用的技术。将上层渲染逻辑和下层资源隔离,进一步的解耦、优化,从而可以多线程和并行渲染。
过程
渲染依赖图系统,运行在pass建立之后。并非立即执行pass,而是延迟到整个帧已记录到依赖性图表数据结构之中后再执行。当完成了对所有pass的收集之后,会执行各类裁剪和优化,可以自动裁减无用的Pass,再按照依赖性的排序顺序对图表进行编译和执行。
具体步骤如下。
图15 RDG过程
收集Pass
:即建立阶段,收集Pass的输入纹理、输出纹理、依赖资源等等,转为RDG Pass
编译Pass
:优化Pass和资源,计算资源生命周期,创建GPU资源
执行Pass
:按照Setup的顺序执行,执行未被剔除的Pass
整个RDG的核心是依赖图(Dependency Graph),可以实现自动异步计算。
帧图依赖关系如图
图16 渲染依赖图
意义
渲染依赖图基本上是现在引擎的标配,通过增加一层调度系统,管理和再使用内存,或执行布局。达到优化内存和减少渲染指令的目的。
总结
本文介绍了虚幻引擎UE的整个渲染框架和基本流程,同时也介绍了渲染优化技术RDG。UE渲染体系复杂而庞大,做了很多优化,为了渲染效果和性能,牺牲了一些灵活性。
本文并未介绍具体技术实现细节,目的是搭好一个框架,能帮助读者有目的性、针对性的深入了解UE渲染,希望勾起读者对研究UE源码的兴趣。
唠嗑
我又回来了,哈哈哈,有三四个月未更文了,中间有不少读者催更过,已经积累了巨大的愧疚感。该来的总会来的。近期求职季,不少读者催面试题的答案版,准备考虑花时间整理下,欢迎有整理过的读者捐献,哈哈哈。
近期Game 104开课了,专门介绍和实现游戏引擎,感兴趣的读者可以试试。
我是五尘,公号 {游戏君五尘},欢迎围观,下期见~
原文链接:虚幻引擎UE渲染架构
参考文献
[1] https://github.com/EpicGames/Signup
[2] https://docs.unrealengine.com/4.27/en-US/
[3] https://www.cnblogs.com/timlly/p/13512787.html
[4]https://epicgames.ent.box.com/s/ul1h44ozs0t2850ug0hrohlzm53kxwrz
原创不易,未经允许,禁止转载、抄袭
上一篇:
零基础能学会虚幻5就业么?
下一篇:
划时代的虚幻5引擎,恐怕撑不起3A梦
回复
举报
使用道具
分享
山水之间大有人
山水之间大有人
当前离线
积分
13
4
主题
6
帖子
13
积分
新手上路
新手上路, 积分 13, 距离下一级还需 37 积分
新手上路, 积分 13, 距离下一级还需 37 积分
积分
13
发消息
发表于 2022-9-20 09:42:11
|
显示全部楼层
支持
回复
举报
使用道具
刘惠亮
刘惠亮
当前离线
积分
23
6
主题
11
帖子
23
积分
新手上路
新手上路, 积分 23, 距离下一级还需 27 积分
新手上路, 积分 23, 距离下一级还需 27 积分
积分
23
发消息
发表于 2022-9-20 09:43:11
|
显示全部楼层
谢谢分享!
回复
举报
使用道具
活碰乱跳的小飞侠
活碰乱跳的小飞侠
当前离线
积分
8
2
主题
5
帖子
8
积分
新手上路
新手上路, 积分 8, 距离下一级还需 42 积分
新手上路, 积分 8, 距离下一级还需 42 积分
积分
8
发消息
发表于 2022-9-20 09:43:49
|
显示全部楼层
写的真好,关注一波[爱]
回复
举报
使用道具
萧源君
萧源君
当前离线
积分
12
2
主题
7
帖子
12
积分
新手上路
新手上路, 积分 12, 距离下一级还需 38 积分
新手上路, 积分 12, 距离下一级还需 38 积分
积分
12
发消息
发表于 2022-9-20 09:44:21
|
显示全部楼层
PreVisibilityFrameSetup执行的是一些渲染参数的初始化,不包含静态网格的处理,ComputeViewVisibility处理所有类型的网格(静态网格和动态网格)
回复
举报
使用道具
网络喷子
网络喷子
当前离线
积分
14
4
主题
7
帖子
14
积分
新手上路
新手上路, 积分 14, 距离下一级还需 36 积分
新手上路, 积分 14, 距离下一级还需 36 积分
积分
14
发消息
发表于 2022-9-20 09:44:34
|
显示全部楼层
RDG 可以插入指定的Pass后面吗,比如自己写的一个pass,插入到Scene里面的BasePass后面或者ShadowDepth后面
回复
举报
使用道具
韦富耀
韦富耀
当前离线
积分
4
1
主题
3
帖子
4
积分
新手上路
新手上路, 积分 4, 距离下一级还需 46 积分
新手上路, 积分 4, 距离下一级还需 46 积分
积分
4
发消息
发表于 2022-9-20 09:45:27
|
显示全部楼层
RDG是对所有pass的统一优化,不是指一个pass
回复
举报
使用道具
返回列表
发新帖
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
|
立即注册
快速回复
返回顶部
返回列表