UE4官方文档中《Graphics Programming Overview》开篇即说:UE4的渲染代码太多故难以从宏观上快速预览它的全貌(There is a lot of rendering code in Unreal Engine 4 (UE4) so it is hard to get a quick high level view of what is going on)。这一官方说辞从侧面说明了UE4渲染引擎的复杂性是很高的,这个说法多少有点推卸责任,也颇具劝退之意。但我们自己做为一个合格的程序员,在做任何技术选型的时候最基本的要求总该是:我选的方案在其内涵和外延上至少要能贴合或拔高项目对该功能块的需求,并且这个方案得是我能全程能Hold得住而不是挖深坑用以自埋的。在这一前提下对UE4的渲染引擎乃至UE4引擎本身做一个宏观的整体性的评估就必不可少了。

当然UE4渲染引擎的FeatureList非常棒且推进迅捷,所以在功能性和前瞻性方面往往大超项目预期,往往并不是评估的重点。许多公司之所以选UE4做为项目的引擎必选项,是因为老板看到基于UE的吃鸡大热,UE4所产出的其它产品和宣传视频也惊艳绝伦,于是乎脑袋一热双手一拍,技术人员就麻着胆子硬着头皮,战战兢兢开始玩弄UE(或者说被UE摁在地上摩擦了)。

本文的内容是从渲染引擎的宏观功能上罗列UE4的覆盖面和划分方式,尚不会涉及到具体每个功能模块的实现细节。本文在讨论渲染模块的时候还假设大家均具备这些图形引擎常识:渲染API的功能范畴、如何组织基础的渲染管线、夸平台图形引擎需要基础框架支持的最小集

先从顶层来看一次完整的渲染

给渲染器输入以原始的几何和材质数据,渲染器把几何和材质数据转换为渲染API所支持的数据、渲染状态、Shader及Shader参数并由这些数据组装为一个RenderPipeline,然后执行该RenderPipeline,得到渲染结果后交换到渲染的目标Context上去(如Windows下的一个窗口,Android下的一个View等)。一个3D渲染引擎的核心工作就是组织好这一宏观上的工作流,使其最大化利用目标平台的硬件资源(CPU,GPU,内存,硬盘或闪存等)和特性,使其使用最便利、性能最优,效果最佳。

UE4的渲染系统也不例外,所以我们的渲染功能的识别方式的基于以上基本过程和传统的3D引擎功能划分来做。UE4的模块(Module)和我们将要讨论的渲染功能模块不存在一一对应关系,可能UE4的一两个类即实现一个功能块,或一个UE4的模块(Module)除了包含数个渲染相关的功能。

UE4场景和场景管理(Scene 、SceneManager)

在UE4中不存在传统引擎中的严格一一对应的Scene和SceneManager,它的实现是散落在许多类中。

传统引擎中的Scene一般表达一个渲染用的世界。这个概念在UE4中有两个类和它对应:用于游戏线程中的UWorld类和用于渲染线程中的FScene类.UE4中的中UWorld和FScene有一一对应关系,UWorld用于游戏线程,用于用户的主动操作(如创建、删除世界中的物件等),而FScene则隐藏于渲染线程,由UWorld和世界中的对象被动操作。在游戏过程中,一般只存在一个UWorld实例(在过渡的时候可能有两个),但在编辑器形态下,一般会存在许多个UWorld对象——一般来说,一个UWorld对象表达一个单独的编辑器窗口。

UE4和其它支持大世界的引擎一样支持游戏场景中的物体动态加载和卸载。但它对于大世界的拆分方式是比较独特的——UE4的场景的划分模式不是基于物件级而是基于子关卡级来做。在UE4中,一个UWorld由一个一直存在的持久关卡(ULevel类)和多个动态加载卸载的子关卡组成。UE4中这种动态加载卸载的子关卡叫做流关卡(StreamingLevel ,ULevelStreaming类),且场景中的具体物件都是放置在关卡或流关卡中而不是直接位于UWorld中。

UE4中的流关卡的加、卸载策略实现是由UWorldComposition类来负责的。这是一个基于视点距离和流关卡卡包围盒的简单的加载策略实现。

用于渲染线程的FScene不具备复杂的场景管理功能,它有一些数组用于各类管理场景可渲染对象和灯光,它有两个Octree结构用于空间的快速查询——一个用于灯光,另一个用于其它的可渲染对象,它还有一个DrawList用于Cache各个渲染Pass的指令。

UE4场景中的物体(SceneObject)

当我们在UE编辑器中往场景里拖一个NPC,或放置一个灯光,一个后处理盒(PostProcess Volume)的时候,我们都是往该关卡中添加了一个AActor子类实例,UE4关卡和流关卡中每一个独立物件由一个AActor及其子类的对象实例来建模表达

AActor及其子类本身并不直接持有渲染所需的数据,AActor基于组合模式设计,可持有数个UActorComponent实例,具体的渲染相关的数据均在UActorComponent及其子类的实例中。

USceneComponent见名知义,它是UActorCompoent子类里可用于场景中的组件基类。USceneComponent有两个主要作用:它包含Transform数据,它可以支持Attachment。

UPrimitiveComponent是USceneComponent的子类,它是所有可渲染组件的基类。它包含一系列的几何数据,而做为附赠品,它同时也可以做为碰撞数据使用。

ULightComponentBase是USceneComponent的另一个子类,它是所有灯光组件的基类。

渲染相关的主要Component类结构层次

UE4要渲染API封装

UE4中的渲染API封装是个独立的模块(Module),他们把它命名为RHI(Render Hardware Interface)。RHI的接口定义上倾向于向最新的渲染API靠近(如DX12和Vulkan),它除了提供渲染API提供的主要接口转发外,还对CommandList,ShaderCache、StateCache和GpuProfiler做了基本的封装。

RHI的转发实现在RHICommandList.h文件里,可以看到其实现除了基本的条件判断,大都是直接 转调渲染API实现的RHI子模块里的渲染指令。

UE4具体的实现了以下RHI模块的封装

D3D11RHI ,基于D3D11 Feature的RHI封装

D3D12RHI,基于D3D12 Feature的RHI封装

MetalRHI,基于Metal 1和2的RHI封装

OpenGLGLDrv ,它同时实现了Windows,Linux,Android,Ios,Web等各个平台的Opengl,包含GL3,GL4.x和GLES2,GLES3和H5上的Feature.

EmptyRHI和NullDrv,这两个都是对RHI的空实现

UE4的材质系统

UE4对材质系统的封装可以理解为RenderPipiline输入的所有数据中除了几何体数据之外的所有其它数据。它包括渲染所需要选择的光照模型、光照自身的照射分布函数、材质模型及该材质模型所需要的输入参数,渲染状态数据,为各种顶点格式和渲染分支生成的Shader,以及一个提供给用户编辑态使用的节点图等等。

UE4中可用于渲染的材质分为两种:一种是材质模板(UMaterial),另一个是基于材质模板的材质实例(UMaterialInstance).这两货都是UMaterialInterface的子类。只有UMaterial材质模板带有可编辑的节点图并可拒此生成对应的Shader组合,而UMaterialInstance材质实例则只需要引用UMaterial对应的Shader.UMaterialInstance只能修改材质模板暴露出来的材质参数。

对渲染层来说,一般并不需要区分材质实例和材质模板本身。

FMaterialResourceFMaterail的子类,用于UMaterial的渲染,具体来说FMaterialResource负责为各个渲染API和材质所支持的各种质量等级生成对应的Shader组合。所以,每个UMaterial都会包含多个FMaterialResource。

FMaterialRenderProxyFMaterial用于渲染线程的代理,它可以透过FMaterail和UMaterialInterface访问到Shader、渲染状态,光照模型等所有用户设置好的材质参数。

UE4的材质中光照模型是不可定制的,所以在不魔改源码的前提下,你无法修改其光照模型,比如你想实现一个NPR的Ramp给光照分层时。

UE4中Shader生成

FShader是UE4中所有Shader的基类,它有两个主要的子类

FGlobalShader:全局Shader,会自动注册到全局ShaderCache中

FMaterialShader:用于材质(编辑器)的Shader,所有的后处理、UI、用于模型渲染的Shader都是它的子类。

UE4 Shader生成分两部分,第一部分是把材质编辑器中的节点图编译成HLSL代码,这一部分是通过FHLSLMaterialTranslator来完成的。

UE4 Shader生成的第二部分是把HLSL生成多平台的Shader代码,如Windows上的HLSL,Android上的GLSL,IOS上的MetalShader,简单的流程是这样:

如果是目标平台是HLSL相关的平台,则使用ShaderCompilerCommon模块编译出HLSL AST,再适配到不同的SM Feature上。

如果目标平台是非HLSL相关的平台,则先通过Hlslcc模块(在源码的ThirdParty中)把HLSL编译成基于Mesa自定义的GLSL ByteCode的AST,对该AST再使用GLSLOptimizer进行优化,并把对应的AST通过不同平台的Shader编译后端把Mesa GLSL ByteCode生成不同的Shader源码。

第二部分编译是通过启动ShaderCompilerWorker实用程序并行编译

ShaderCompilerWorker的只是简单封装了一下就转调了IShaderFormat的各个子类的CompileShader,而ShaderFormat则会调用对应的xxxxFrontend(FOpenGLFrontend)进行具体的Shader生成。

基本生成流程如下图

从上面的介绍可以看到UE4的Shader跨平台方案,和U3D一样,使用的字节码的方案,不过一个用的是HLSL BC,一个使用的是Mesa BC。Shader Cross Compile在有了Spir-v之后或者大家都往其迁移是更靠谱的方式——毕竟这是个有强大开源组织在维护、升级和推动的天然跨平台的字节码,而且其Optimizier也在持续维护,要比目前的UE使用的glsloptimizer可维护性会更好。

关于Shader编译的细节和优化、后续还会有文章详细介绍,而这篇文章的字数看起来也比较有点多了,所以就此打住,更多的关于UE4渲染模块的简介也在后面的文章里再续。

opengl游戏引擎源码_UE4渲染引擎模块简介(1)相关推荐

  1. 3D游戏引擎系统源码C++本科毕业设计,C++ 3D引擎源码,渲染系统使用的OpenGL 及 OpenGL ES

    Effective 3D Engine 渲染系统使用的OpenGL 及 OpenGL ES,Windows上OpenGL ES使用AMD的ES模拟器. 环境部署 完整代码下载地址:3D游戏引擎系统源码 ...

  2. opengl游戏引擎源码_渲染概念:1.引擎二三事

    书写本文的初衷是为了自我记录与学习,同时分享认识更多的朋友. 引擎与图形学 常说的引擎指什么? 游戏引擎 渲染引擎 引擎与图形学 图形学一般最开始先了解的是图形API,Opengl.DX以及Metal ...

  3. cocos creator 游戏源码_Cocos Creator 3D引擎源码阅读之授之以渔 源码阅读

    源码阅读 动静之法 静 找到引擎源码的所在 在编辑器的右上角有一个大按钮 在VSCode里开打engine目录 引擎源码就在红色标中的cocos文件夹里,如下图 让我们来看一下引擎的目录结构 可以看到 ...

  4. UWA学堂上新|虚幻引擎源码解析——基础容器篇

    文章简介 文章主要介绍了虚幻引擎的基础容器的内部数据结构和实现原理,以及在实践中的应用,性能优化等方面.包括:TArray.TSparseArray.TSet.TMap等基础容器,TQueue.TTr ...

  5. 【Unity开源项目精选】Unity引擎源码的C#部分

    洪流学堂,让你快人几步.你好,我是你的技术探路者郑洪智,你可以叫我大智. 今天给你分享一个Unity开源项目,我们一起来看看吧! Unity引擎源码的C#部分 Unity 引擎和编辑器源代码的 C# ...

  6. 【开源】微信小程序、小游戏以及 Web 通用 Canvas 渲染引擎 - Cax

    Cax 小程序.小游戏以及 Web 通用 Canvas 渲染引擎 Github → github.com/dntzhang/ca- 综合 DEMO | 运动 DEMO 小程序 DEMO 正在审核中敬请 ...

  7. html5 2d小游戏,cax: HTML5 Canvas 2D Rendering Engine - 小程序、小游戏以及 Web 通用 Canvas 渲染引擎...

    Cax 小程序.小游戏以及 Web 通用 Canvas 渲染引擎 微信小游戏 特性 Learn Once, Write Anywhere(小程序.小游戏.PC Web.Mobile Web) Writ ...

  8. html集成到小程序1011无标题,GitHub - billee1011/cax: 小程序、小游戏以及 Web 通用 Canvas 渲染引擎...

    Cax 小程序.小游戏以及 Web 通用 Canvas 渲染引擎 小程序 DEMO 正在审核中敬请期待 小游戏 DEMO 正在审核中敬请期待 特性 Learn Once, Write Anywhere ...

  9. 【开源】微信小程序、小游戏以及 Web 通用 Canvas 渲染引擎 - Cax 1

    Cax 小程序.小游戏以及 Web 通用 Canvas 渲染引擎 Github → https://github.com/dntzhang/cax 点我看看 DEMO 小程序 DEMO 正在审核中敬请 ...

最新文章

  1. 史上最详细的值传递和引用传递之间区别
  2. Word英文句子之间空两格的方法,有截图
  3. R和RStudio下载安装详细步骤
  4. 百度api 一直提示token错误_phpcms小程序插件小程序万能接口api(支持微信、百度)...
  5. centos PIL 安装
  6. 大二第二学期周学习进度总结(十三)
  7. layui中折叠面板的使用
  8. 【“新智认知”杯上海大学联赛】E-CSL的魔法(序列b到序列b‘需要的数据交换次数)
  9. 水系图一般在哪里找得到_水系电池再发Nature,事实力证将迎来发展的春天!
  10. [面试]HR最常用的20个面试问题及答案
  11. python求角度_python根据坐标点的坐标计算角度
  12. 如何压缩PPT文档的大小
  13. 查询数据库各种历史记录
  14. 手机上测试东南西北方向软件,指南针怎么看东南西北(手机指南针怎么看图解)...
  15. 如何快速将CAD图纸转换成PDF文件?
  16. 我经历的IT公司面试及离职感受
  17. 计算机教室架构,物联网智慧教室架构
  18. 科学上网后(关掉VPN)之后无法正常连接网络
  19. openBoard开源白板项目
  20. 支付宝小程序对接流量位详细教程

热门文章

  1. 疫情之后,出行市场的春天还有多远?
  2. php 自动测试,PHP自动化测试
  3. html5语义化布局分割代码,HTML5语义化标签布局的兼容性.html
  4. java文件出现字符串_找出三个文本文件中都出现的字符串,并输出到一个文本文件(菜鸟求救)...
  5. Mysql基础--常见的表的约束介绍(一)
  6. 全面讲解Python列表数组(四)什么是元组?元组跟列表数组的差异?元组的特征符号是啥子?
  7. 用Python3解析html的几种操作方式,你都会用吗?
  8. 相关与卷积(数字信号处理)的数学原理及 Python 实现
  9. android realmax sdk,RealMax推出全新开源AR SDK 框架ARToolKit
  10. C语言ftell()函数(返回文件当前位置)(返回给定流 stream 的当前文件位置)