@author: 黑袍小道

随缘查看

 
 

说明

由于搬山的渲染这部分担心自己理解错误,故而搬移官方下,后面整个完成再反过来更新

(这当且仅当做Unreal的帮助文档)。

 
 

图形编程

模块

渲染器代码存在于其自身的模块中。此模块将编译为非单块版本的一个 dll 文件。这可以使迭代更快,因为在渲染代码变更时无需重新链接整个应用程序。渲染器模块取决于引擎,因为其拥有许多向引擎的回调。然而当引擎需要调用渲染器中的某些代码时,这会通过某个接口来完成,通常为 IRendererModule 或 FSceneInterface。

场景代表

在 UE4 中,渲染器所见的场景由基本组件和 FScene 中存储的多种其他结构的列表定义。将维护一个基元的八叉树,用于加速空间查询。

主要场景类

UE4 中拥有和游戏线程并行运行的渲染线程。

主要的类为:

描述

UWorld

包含多个可交互的 Actor 和组件的世界场景。关卡可以流送进入和退出世界场景,且程序中可以同时有多个世界场景处于激活状态。

ULevel

一同加载/卸载并保存在同一地图文件中的 Actor 和组件合集。

USceneComponent

需要添加到 FScene 中的任意对象的基础类,如光照、网格体、雾等。

UPrimitiveComponent

可渲染或进行物理交互的任意资源的基础类。也可以作为可视性剔除的粒度和渲染属性规范(投射阴影等)。与所有 UObjects 一样,游戏线程拥有所有变量和状态,渲染线程不应直接对其进行访问。

ULightComponent

代表光源。渲染器负责计算和添加其对场景的贡献。

FScene

UWorld 的渲染器版本。对象仅在其被添加到 FScene(注册组件时调用)后才会存在于渲染器中。渲染线程拥有 FScene 中的所有状态,游戏线程无法直接对其进行修改。

FPrimitiveSceneProxy

UPrimitiveComponent 的渲染器版本,为渲染线程映射 UPrimitiveComponent 状态。存在于引擎模块中,用于划分为子类以支持不同类型的基元(骨架、刚体、BSP 等)。实现某些非常重要的函数,如 GetViewRelevance、DrawDynamicElements 等。

FPrimitiveSceneInfo

内部渲染器状态(FRendererModule 实现专有),对应于 UPrimitiveComponent 和 FPrimitiveSceneProxy。存在于渲染器模块中,因此引擎看不到它。

FSceneView

单个视图到一个 FScene 的引擎代表。视图可以通过对 FSceneRenderer::Render 的不同调用的不同视图来渲染(多编辑器视口)或通过对 FSceneRenderer::Render 的同一调用中的多个视图来渲染(分屏游戏)。为每个帧构建新视图。

FViewInfo

视图的内部渲染器代表,存在于渲染器模块中。

FSceneViewState

ViewState 存储有关在多个帧中需要的某个视图的私有渲染器信息。在游戏中,每个 ULocalPlayer 只有一个视图状态。

FSceneRenderer

为每个帧创建的类,用于封装跨帧的临时对象。

下面按其所在的模块列出了各种主类。

引擎模块

渲染器模块

UWorld

FScene

UPrimitiveComponent / FPrimitiveSceneProxy

FPrimitiveSceneInfo

FSceneView

FViewInfo

ULocalPlayer

FSceneViewState

ULightComponent / FLightSceneProxy

FLightSceneInfo

以及相同类(按哪个线程对其状态拥有所有权进行排列)。

游戏线程

渲染线程

UWorld

FScene

UPrimitiveComponent

FPrimitiveSceneProxy / FPrimitiveSceneInfo

  

FSceneView / FViewInfo

ULocalPlayer

FSceneViewState

ULightComponent

FLightSceneProxy / FLightSceneInfo

 
 

材质类

描述

FMaterial

连接用于渲染的材质的接口。可用于访问材质属性(如混合模式)。包含被渲染器用于检索个体着色器的着色器地图。

FMaterialResource

UMaterial 的 FMaterial 接口实现。

FMaterialRenderProxy

材质在渲染线程上的代表。可用于访问 FMaterial 接口和各个标量、向量和纹理参数。

UMaterialInterface

[abstract] 用于材质功能的游戏线程接口。用于检索用于渲染的 FMaterialRenderProxy 和用作来源的 UMaterial。

UMaterial

材质资源。授权为节点图形。计算用于着色、设置混合模式等的材质属性。

UMaterialInstance

[abstract] UMaterial 的实例。使用 UMaterial 中的节点图形,但提供不同参数(标量、向量、纹理、静态切换)。每个实例都有一个父项 UMaterialInterface。因此,材质实例的父项可能是 UMaterial 或另一个 UMaterialInstance。这会形成一个链,最终通往 UMaterial。

UMaterialInstanceConstant

只能在编辑器中修改的 UMaterialInstance。可以提供标量、向量、纹理和静态开关参数。

UMaterialInstanceDynamic

可以在运行时修改的 UMaterialInstance。可提供标量、向量和纹理参数。无法提供静态开关参数,且无法成为另一 UMaterialInstance 的父项。

 
 

基元组件和代理

基元(就是Prim)组件是可视性和相关性确定的基本单位。例如,遮蔽和视锥剔除都是按基元进行的。因此在设计系统时,考虑组件的大小十分重要。每个组件都有一个边界,用于多种操作,如剔除、阴影投射和光照影响确定。

组件只有在注册之后才会对场景(以及渲染器)可见。

更改组件属性的游戏线程代码必须调用组件上的 MarkRenderStateDirty(),将更改传播到渲染线程。

FPrimitiveSceneProxy 和 FPrimitiveSceneInfo

FPrimitiveSceneProxy 是 UPrimitiveComponent 的渲染线程版本,用于根据组件类型划分子类。

它存在于引擎模块中,并在渲染通道中调用函数。

FPrimitiveSceneInfo 是基元组件状态,为渲染器模块私有。

重要的 FPrimitiveSceneProxy 方法

函数

描述

GetViewRelevance

在帧的开始从 InitViews 调用,并返回填充的 FPrimitiveViewRelevance。

DrawDynamicElements

调用,以便在某代理相关的任何通道中绘制该代理。仅在代理表示自己拥有动态相关性时调用。

DrawStaticElements

调用以在基元与游戏线程相连时提交代理的 StaticMesh 元素。仅在代理表示自己拥有静态相关性时调用。

 
 

场景渲染顺序

渲染器按照其希望将数据整合给渲染目标的顺序处理场景。例如,仅 Depth 的通道会比 Base 通道先渲染,先填充 Heirarchical Z (HiZ),从而降低基础通道中的着色消耗。此顺序是按通道函数在 C++ 中调用的顺序静态决定的。

相关性

FPrimitiveViewRelevance 是说明通道与基元相关的信息。基元可能有存在不同相关性的多个元素,因此 FPrimitiveViewRelevance 相当于一个所有元素的相关性的逻辑 OR。这表示基元可以同时存在不透明和透明相关性,或动态和静态相关性;它们并非相互排斥。

FPrimitiveViewRelevance 还会显示基元是否需要使用动态 (bDynamicRelevance) 和/或静态 (bStaticRelevance) 渲染路径。

绘制规则

绘制规则包括通过通道特定的着色器渲染网格体的逻辑。它们使用 FVertexFactory 接口来抽取网格体类型,并使用 FMaterial 接口来抽取材质详情。在最底层,一条绘制规则会负责一组网格体材质着色器以及一个顶点工厂,将顶点工厂的缓冲区与渲染硬件接口 (RHI) 绑定,将网格体材质着色器与 RHI 绑定,设置适当的着色器参数,然后执行 RHI 绘制调用。

绘制规则方法

函数

描述

Constructor

从给定的顶点工厂和材质着色器地图,并存储这些引用。

CreateBoundShaderState

为绘制规则创建 RHI 边界着色器状态。

Matches/Compare

提供排列绘制规则与静态绘制列表中的其他项目的方法。Matches 必须比较 DrawShared 依赖的所有因素。

DrawShared

设置在从 Matches 返回 True 的绘制规则之间一致的 RHI 状态。例如,大多数绘制规则会为材质和顶点工厂排序,因此着色器参数只依赖可以设置的材质,并且可以绑定特定于该顶点工厂的顶点缓冲区。应尽可能在此处设置状态,而非在 SetMeshRenderState 设置,因为 DrawShared 在静态渲染路径中调用较少。

SetMeshRenderState

设置特定于此网格体的 RHI 状态,或 DrawShared 中未设置的任何项目。这比 DrawShared 调用的次数多得多,因此此处性能非常重要。

DrawMesh

实际发出 RHI 绘制调用。

 
 

渲染路径

UE4 拥有动态路径(能够提供更多的控制,但转换较慢)和静态渲染路径(缓存尽可能靠近 RHI 级别的场景转换)。差异基本上是整体上的,因为它们都在最底层使用绘制规则。应确保各个渲染通道(绘制规则)在需要时能够同时处理两个渲染路径。

动态渲染路径

动态渲染路径使用 TDynamicPrimitiveDrawer 并对每个要渲染的基元场景代理调用 DrawDynamicElements。需要使用动态路径来渲染的一组基元通过 FViewInfo::VisibleDynamicPrimitives 来跟踪。每个渲染通道都需要在此阵列上迭代,并调用各个基元上的 DrawDynamicElements。随后,代理的 DrawDynamicElements 需按需要组合出多个 FMeshElements,并将其随 DrawRichMesh 或 TDynamicPrimitiveDrawer::DrawMesh 提交。这样最终会创建一个新的临时绘制规则,调用 CreateBoundShaderState、DrawShared、SetMeshRenderState 以及 DrawMesh。

静态渲染路径

静态渲染路径通过静态绘制列表实现。网格体在连接到场景时会插入到绘制列表中。在插入过程中,将调用代理上的 DrawStaticElements,以收取 FStaticMeshElements。随后将随 CreateBoundShaderState 的结果创建并存储一个绘制规则实例。新的绘制示例将根据其 Compare 和 Matches 函数排序,并插入到绘制列表中的适当位置(参见 TStaticMeshDrawList::AddMesh)。在 InitViews 中,包含静态绘制列表中的可见性数据的 bitarray 会初始化并传递到 TStaticMeshDrawList::DrawVisible(实际绘制绘制列表的地方)。DrawShared 只会对所有相互匹配的绘制规则调用一次,而 SetMeshRenderState 和 DrawMesh 会对每个 FStaticMeshElement(参见 TStaticMeshDrawList::DrawElement)调用。

静态渲染路径会将许多工作移动连接时间,这会大大加快渲染时的场景转换。在渲染线程上针对静态网格体时,静态绘制列表的渲染会快 3 倍,从而允许场景中出现多得多的静态网格体。由于静态绘制列表会在连接时间缓存数据,因此它们仅能缓存与视图无关的状态。很少重新连接但经常需要渲染的基元非常适合静态绘制列表。

静态渲染路径可能会暴露出 bug,因为它每个状态桶只调用 DrawShared 一次。这些 bug 可能会很难发现,因为它们取决于场景中网格体的渲染顺序和连接顺序。特别的视图模式(如仅光照、无光照等)会强制所有基元使用动态路径,因此如果在强制动态渲染路径时 bug 消失,则其很可能是由于某绘制规则的 DrawShared 和/或 Matches 函数的错误实现而出现的。

总体渲染顺序

下面将说明从 FDeferredShadingSceneRenderer::Render 开始渲染一个帧时的控制流程:

操作

描述

GSceneRenderTargets.Allocate

按需要重新分配全局场景渲染目标,使其对当前视图足够大。

InitViews

通过多种剔除方法为视图初始化基元可见性,设立此帧可见的动态阴影、按需要交叉阴影视锥与世界场景(对整个场景的阴影或预阴影)。

PrePass / Depth only pass

RenderPrePass / FDepthDrawingPolicy。渲染遮挡物,对景深缓冲区仅输出景深。该通道可以在多种模式下工作:禁用、仅遮蔽,或完全景深,具体取决于活动状态的功能的需要。该通道通常的用途是初始化 Hierarchical Z 以降低 Base 通道的着色消耗(Base 通道的像素着色器消耗非常大)。

Base pass

RenderBasePass / TBasePassDrawingPolicy。渲染不透明和遮盖的材质,向 GBuffer 输出材质属性。光照图贡献和天空光照也会在此计算并加入场景颜色。

Issue Occlusion Queries / BeginOcclusionTests

提出将用于下一帧的 InitViews 的延迟遮蔽查询。这会通过渲染所查询物体周围的相邻的框、有时还会将相邻的框组合在一起以减少绘制调用来完成。

Lighting

阴影图将对各个光照渲染,光照贡献会累加到场景颜色,并使用标准延迟和平铺延迟着色。光照也会在透明光照体积中累加。

Fog

雾和大气在延迟通道中对不透明表面进行逐个像素计算。

Translucency

透明度累加到屏外渲染目标,在其中它应用了逐个顶点的雾化,因而可以整合到场景中。光照透明度在一个通道中计算最终光照以正确融合。

Post Processing

多种后期处理效果均通过 GBuffers 应用。透明度将合成到场景中。

以上是相当简单概略的介绍。如需了解详情,请通读相关代码或输出的"profilegpu"日志。

渲染硬件接口 (RHI)

RHI 是平台特定的图形 API 之上的一个薄层。UE4 中的 RHI 抽象层尽可能低,这样大多数功能都能以与平台无关的代码写成,从而能够在支持所需功能层级的任何平台上运行。

功能集将量化到 ERHIFeatureLevel 中,降低复杂程度。如果平台无法支持某个功能层级所需的全部功能,则其必须降低层级,直至能够全部支持。

功能层级

描述

SM5

通常对应于 D3D11 Shader Model 5,但由于 OpenGL 4.3 限制,仅有 16 种纹理可以使用。支持曲面细分、计算着色器和立方体贴图阵列。支持延迟着色路径。

SM4

对应 D3D11 Shader Model 4,这与 SM5 基本相同,但没有曲面细分、计算着色器和立方体贴图阵列。支持延迟着色路径。不支持眼适应,因为其使用计算着色器。

ES2

对应大多数 OpenGL ES2 移动设备支持的功能。使用削减向前着色路径。

渲染状态分组

渲染状态根据其影响的流程部分而分组。例如,RHISetDepthState 可设置所有与景深缓冲相关的状态。

渲染状态默认值

由于渲染状态数量众多,要在每次绘制之前对它们全部设置一遍是不现实的。为此,UE4 具有隐性设置的一组状态,它们被认为是设置为了默认值(因此在变更后必须恢复为默认值),另外还有一组少得多的状态需要显性设置。没有隐性默认值的状态有:

  • RHISetRenderTargets
  • RHISetBoundShaderState
  • RHISetDepthState
  • RHISetBlendState
  • RHISetRasterizerState
  • 由 RHISetBoundShaderState 设置的着色器的任何依赖性

    其他所有状态均视为已设置为其默认值(即相关 TStaticState 的定义,如默认的蜡纸模板状态由 RHISetStencilState(TStaticStencilState<>::GetRHI()) 设置。

(整)Unreal渲染模块 框总览的更多相关文章

  1. (原)Unreal 渲染模块引言Temp

            @author:白袍小道     引言 本文只在对Unreal渲染模块做一些详细的理解,务求能分析出个大概. 其中框架的思想和实现的过程,是非常值得学习和推敲一二的. 涉及资源系统,材 ...

  2. (原)Unreal渲染模块 管线 - 着色器(1)

    @author: 白袍小道 转载悄悄说明下 随缘查看,施主开心就好 说明: 本篇继续Unreal搬山部分的渲染模块的Shader部分, 主要牵扯模块RenderCore, ShaderCore, RH ...

  3. (原)Unreal渲染模块 管线 - 程序和场景查询

    @author: 白袍小道 查看随意,转载随缘     第一部分: 这里主要关心加速算法,和该阶段相关的UE模块的结构和组件的处理. What-HOW-Why-HOW-What(嘿嘿,老规矩) 1.渲 ...

  4. (原)Unreal 渲染模块 渲染流程

    @author:白袍小道 浏览分享随缘,评论不喷亦可.     扯淡部分: 在temp中,乱七八糟的说了下大致的UE过程.下面我们还是稍微别那么任性,一步步来吧.     UE渲染模块牵扯到场景遍历. ...

  5. (原)Unreal渲染模块 源码和实例分析说明

    @author:白袍小道 说明 1.由于小道就三境武夫而已,而UE渲染部分不仅管理挺大,而且牵扯技术和内容驳杂,所以才有这篇梳理. 2.尽量会按书籍和资料,源码,小模块的调试和搬山(就是敲键盘)..等 ...

  6. (原、整)Unreal源码 CoreUbject- Uobject

    (原.整) Unreal源码 CoreUbject- Uobject 类别                    [随笔分类]Unreal源码搬山 @author:白袍小道 随缘那啥 这里还是属于UE ...

  7. django-rest-framework-源码解析002-序列化/请求模块/响应模块/异常处理模块/渲染模块/十大接口

    简介 当我们使用django-rest-framework框架时, 项目必定是前后端分离的, 那么前后端进行数据交互时, 常见的数据类型就是xml和json(现在主流的是json), 这里就需要我们d ...

  8. Django---Http协议简述和原理,HTTP请求码,HTTP请求格式和响应格式(重点),Django的安装与使用,Django项目的创建和运行(cmd和pycharm两种模式),Django的基础文件配置,Web框架的本质,服务器程序和应用程序(wsgiref服务端模块,jinja2模板渲染模块)的使用

    Django---Http协议简述和原理,HTTP请求码,HTTP请求格式和响应格式(重点),Django的安装与使用,Django项目的创建和运行(cmd和pycharm两种模式),Django的基 ...

  9. DRF框架(一)——restful接口规范、基于规范下使用原生django接口查询和增加、原生Django CBV请求生命周期源码分析、drf请求生命周期源码分析、请求模块request、渲染模块render

    DRF框架    全称:django-rest framework 知识点 1.接口:什么是接口.restful接口规范 2.CBV生命周期源码 - 基于restful规范下的CBV接口 3.请求组件 ...

随机推荐

  1. BestCoder Round #89 1001 Fxx and string

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5944 分析: 竟然 i,j,k成等比数列,即i*k = j*j,还要满足 j|i or j|k. 不防 ...

  2. vuejs父子组件的数据传递

    在vue中,父组件往子组件传递参数都是通过属性的形式来传递的 <div id='root'> <counter :count = '1'></counter> &l ...

  3. VedioCapture

    国内的技术的浮躁可见一般,在一个用了七八年的项目里面使用的类,居然拼写都是错的,在网上一搜,转载的也大有人在,最低级的错误,你可以不懂编程,但是只要上过高中,Video这个单词总该学过吧,居然转载的时 ...

  4. Java解析Excel工具类(兼容xls和xlsx)

    依赖jar <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml&l ...

  5. 使用maven搭建ssm项目配置+tomact

    一.代码自动配置:https://www.cnblogs.com/weibanggang/p/10043201.html 二.手动配置 1.创建好maven项目,在pom.xml配置文件 <!- ...

  6. img适配问题解决方法

    将img放到background中,将background-size设置为100%:只需要适配背景为img的元素的宽和高即可.

  7. 大白话讲解BP算法(转载)

    最近在看深度学习的东西,一开始看的吴恩达的UFLDL教程,有中文版就直接看了,后来发现有些地方总是不是很明确,又去看英文版,然后又找了些资料看,才发现,中文版的译者在翻译的时候会对省略的公式推导过程进 ...

  8. html和node.js实现websocket

    websocket websocket是HTML5开始提供的一种单个TCP连接上进行全双工通讯的协议.它让客户端和服务端之间的数据交换变得更加简单,允许服务端主动向客户端推送数据.浏览器和服务器只需要 ...

  9. ABAP 调用远程rfc

    ABAP 调用rfc DESTINATION附加项后面接的是远程目标名称,该目标在事务SM59中设定,其中包含连接和登录远程系统所需的全部参数信息.如果调用的就是本机的RFC目标,则DESTINATI ...

  10. 史上最强大的wordpress后台框架redux-framework安装及使用

    redux-framework的相关链接 Redux的官方网站:https://reduxframework.com/ Redux文档查询:https://docs.reduxframework.co ...