qt 读取gif一帧_译:Unreal渲染一帧详解(Unreal Frame Breakdown)
译者前言:
上一篇文章,我补充翻译了”How Unreal renders 1 Frame?”的第三篇,在找资料过程中,又发现了一篇挺好的文章,同样是基于”How Unreal renders 1 Frame?”来进行了更进一步的尝试和分析,觉得可以把这篇文章也翻译一下,从而方便更多的读者。
这篇文章的优势主要是给出了一些更细致的GIF贴图,一一种动态的方式来让大家更好地来理解整个渲染过程。当然,在一些理论知识上的介绍,比原有的博文介绍的比较简单,大家最好对照着来看。毕竟两个场景是比较类似的。
原文链接:
Unreal Frame Breakdownviclw17.github.io
作者:Victor Li,似乎是个华人,这是在他的技术BLog上发表的。
-----------------------------------------------------------------------------------------------
原文
这个是我自己版本的“How Unreal Render One Frame?”,我试着按照这篇博文来profile一帧来学习延迟渲染的整个过程。
我按照这篇blog来构建了一个测试的场景。首先将Unreal设置为”延迟渲染“,如果设置为”forward rendering“的话,整个渲染过程会有非常大的差异,后面我也会来介绍一下这个渲染管线。在我的测试例子中,umap被命名为NewWorld。它包含以下内容:
- 1个方向灯,从左上到右下
- 1静态光,白色
- 2个固定灯,均为蓝色
- 2个移动灯,一绿一红
- 标记为可移动的岩石网格
- 其余所有网格都是静态的
- 所有带有阴影的网格
- 1个火粒子系统
- 体积照明
- 天空盒
1、Particle PreRender
在GPU上进行粒子模拟(只有GPU Sprites Particle类型的粒子)。因为我们在粒子系统中有两个GPU粒子发射器,所以,粒子模拟的pass有了两个Draw Call。
EID | Event | Draw # | Duration (Microseconds)| - GPUParticles_PreRender | 2 | 36.864| - GPUParticles_SimulateAndClear | 2 | 23.552| - ParticleSimulationCommands | 2 | 23.552| - ParticleSimulation | 2 | 23.552
115 | - DrawIndexed(48) | 2 | 23.552
121 | - API Calls | 3 | 0.00| - ParticleSimulation | 4 | 13.312
138 | - DrawIndexed(48) | 4 | 13.312
144 | - API Calls | 5 | 0.00
148 | - API Calls | 6 | 0.00
这个Pass会输出下面2个Render Target(RT):
1、RT0: 粒子的位置信息
2、RT1:粒子的速度信息
2、PrePass
PrePass获取所有不透明的(例如,使用opaque或masked的材质)mesh,并输出 Depth Z pass(Z-prepass)。 DBuffer需要其结果,也就是“ Forced by DBuffer”,这个过程也可以通过启动Forward Shading来启动。 pre-pass也可以被用于遮挡剔除来使用。
请注意,椅子/雕塑/窗户墙/地板+天花板都是成对的,因此它们被渲染为每一对“ 2个实例”,每对仅引起1个Draw Call。 这是实例化的一种证明,它可以通过节省调用次数来进行优化。
还要注意一个有趣的细节-此过程对所有Mesh使用WorldGridMaterial材质(引擎默认材质)来进行渲染。
3、ComputeLightGrid*
这个功能会优化Forward Shading中的光照处理。 根据unreal源代码中的注释,这个pass“将本地灯光(点光源和聚光灯光源)裁剪后,存储在视锥空间中的网格中。 使用“表面照明模式(Surface Lighting Mode)”来处理Forward Shading或半透明”。 换句话说:它将光分配给网格中的单元(沿摄像机视图而形成金字塔形状网格)。 此操作有一定的成本,但会在以后获得回报,从而更快地确定哪些灯光会影响哪些网格。 参考信息:Source
4、BeginOcclusionTests
术语“遮挡剔除”是指一种方法,如果对象被其他对象遮挡,则通过从渲染管线中消除对象来尝试减少图形系统上的渲染负载。 有几种方法可以做到这一点。
- 启动遮挡查询。
- 关闭对帧和深度缓冲区的写入,并禁用任何多余的状态。 因此,现代图形硬件能够以更高的速度光栅化(NVIDIA 2004)。
- 针对复杂对象,只渲染一个简单但保守的近似值(通常是一个bounding box:GPU计算实际上已经通过深度测试的Fragment总数);
- 终止遮挡查询。
- 询问查询结果(即近似几何图形的可见像素数)。
- 如果计算出来需要绘制的像素数大于某个阈值(通常为零),则需要渲染原本比较复杂的对象。
Chapter 6. Hardware Occlusion Queries Made Usefuldeveloper.nvidia.com
该Pass起步于2个ShadowFrustumQueries,然后是1个GroupedQueries,最后是一个IndividualQueries。
4.1、ShadowFrustumQueries
第一组2个ShadowFrustumQueries用于2个可移动点光源,因此,Frustum是一个球体。第二组3个ShadowFrustumQueries用于2个固定点光源和1个方向光(1个static light是通过烘焙贴图生成),对于这些情况,视锥是截顶的金字塔(请注意,定向光的视锥非常长)。
4.2、GroupedQueries
这是用于遮挡的对象。在我的场景中,墙后面的桌子网格被完全遮挡,因此在此步骤中显示出来。
4.3、IndividualQueries
这适用于所有其他对象,并且注意遮挡测试在边界框上完成。
5、BuildHZB
此步骤将生成Hierarchical Z缓冲区。这将Z-prepass过程中产生的深度缓冲区用作输入,并创建深度的mipmap chain(即,对其进行连续降采样)。
6、ShadowDepths
此步骤仅适用于可移动对象,因为应实时计算其阴影情况。所有静态对象阴影都应预先烘焙以节省性能。在这种情况下,对Rock网格进行以下所有计算,因为它被标记为可移动对象。大家可以从下图中看到,对于Rock,它与所有的Light来进行阴影的计算。
对于1个定向灯和2个固定灯,阴影深度将写入Atlas0。一个光源对应一个阴影深度图。
2个可移动灯的处理方式不同。他们正在使用立方体贴图来记录阴影深度。对于每盏灯,首先,CopyCachedShadowMap输出没有可移动对象的立方体贴图。
然后,Unreal将可移动对象的阴影深度再添加到立方体贴图中。
7、Volumetric Fog*
参考资料docs.unrealengine.com
7.1、初始化Volume属性*
此Pass计算雾参数并将其(散射和吸收)存储到Volume纹理中,还将全局emissive值(Global Emissive Value)存储到第二个Volume纹理中。
请注意,在测试场景中,我放置了1 AtmosphereFog和1 ExponentialHeightFog。它们是不同的实体,在此过程中已计算出ExponentialHeightFog。AtmosphereFog更像是天空盒(或用于IBL的立方体贴图),稍后将在Atmosphere Pass处理。
7.2、光散射*
该Pass计算在上面的ComputeLightGrid遍历期间分配给光照体积纹理的阴影方向光,Sky light和Local light的每个单元的光散射和消光。它还使用历史缓冲区(本身是3D纹理)在计算着色器输出(光散射,消光)上使用时间抗锯齿,可改善每个网格单元的散射光质量。
7.3、最终整合*
此过程仅在Z维度上对3D纹理进行raymarch,并累积散射的光和透射率,并将结果存储到相应的单元格中。
8、BasePass
这是渲染不透明材料,读取静态光并将其保存到G缓冲区的主要步骤。如我们所见,在渲染之前,已清除了GBuffer中的6个渲染目标。
这些对象上用于最终渲染的actual materials:M_Basic_Floor,M_Chair,M_Brick_Clay_Old,M_Statue,M_Rock_Marble_Polished,M_Rock,M_Wood_Walnut,M_Wood_Walnut。结果,此过程受着色器复杂性的影响很大。还要注意,这个pass中,每个drawcall是基于每种材质的,而不是像Z-prepass中那样是基于Mesh的实例。因此,在渲染优化的过程中,请注意Mesh上的材质插槽数量。
不同G缓冲区渲染目标的示例:材质基础颜色/法线/材质属性/烘焙的照明。
注意,大多数时候,缓冲器的不同通道具有不同的编码信息。我们可以从以下引擎代码中查看详细信息DeferredShadingCommon.ush
:
/** Populates OutGBufferA, B and C */
void EncodeGBuffer(...)
{...OutGBufferA.rgb = EncodeNormal( GBuffer.WorldNormal );OutGBufferA.a = GBuffer.PerObjectGBufferData;OutGBufferB.r = GBuffer.Metallic;OutGBufferB.g = GBuffer.Specular;OutGBufferB.b = GBuffer.Roughness;OutGBufferB.a = EncodeShadingModelIdAndSelectiveOutputMask(GBuffer.ShadingModelID, GBuffer.SelectiveOutputMask);OutGBufferC.rgb = EncodeBaseColor( GBuffer.BaseColor );OutGBufferC.a = GBuffer.GBufferAO;OutGBufferD = GBuffer.CustomData;OutGBufferE = GBuffer.PrecomputedShadowFactors;...
}
9、Velocity
保存每个顶点的速度(稍后用于运动模糊和时间抗锯齿)。
10、AO
在此Pass中,LightCompositionTasks_PreLighting主要计算AmbientOcclusion。首先输出低分辨率AO,然后输出高分辨率AO,最后将结果应用于场景颜色。
11、Lighting
终于到了处理光照的部分了,在这个pass中,unreal将计算Lighting信息,并将其应用到场景中。
11.1、Non Shadowed Lights
首先,Pass将处理NonShadowedLights。非阴影光包括:
- 简单的灯光,例如每个粒子照明,以及
- 不产生阴影的正常场景灯。
两者之间的区别在于,普通场景灯光在渲染时会使用depth bounds test,以避免对Light bound之外的像素进行光照处理。
在StandardDeferredSimpleLights中,每个DrawIndexed用于每个粒子光。如我们所见,它们是按每个粒子处理的,非常昂贵。因此,应该尽量避免使用过多的粒子照明。
Lighting被计算到到SceneColourDeferred缓冲区中。
11.2 Shadowed Lights
11.3、Inject Translucent Volume
虚幻技术对半透明表面进行照明的方法包括将光注入2个体积纹理中。这两个纹理存储到达每个体积单元(纹理TranslucentVolumeX)的光(阴影+衰减)的球谐函数表示以及每个光源的近似光方向(纹理TranslucentVolumeDirX)。
渲染器维护两组这样的纹理,一组用于靠近需要更高分辨率照明的相机道具,另一组用于更远距离的对象,而高分辨率照明并不那么重要。
请注意,从之前的NonShadowedLights传递来看,似乎简单的灯光似乎根本没有写入半透明的灯光体积,因此InjectSimpleLightsTranslucentLighting为空。
11.3、Shadowed Lights
此遍历是在每个灯光上完成的-1个方向光、2个固定光和2个可移动光,因为它们都是投射阴影的。对于每盏灯,都需要执行以下步骤:
- ShadowProjectionOnOpaque - 不透明阴影投影
- InjectTranslucentVolume - 注入半透明体积
- StandardDeferredLighting - 标准延迟照明
作为最后一步,在FilterTranslucentVolume中过滤(对于两个级联)半透明照明体积(translucency lighting volumes),以在处理半透明道具/效果的照明效果时,抑制锯齿效果。
12、Reflection
在这个阶段,Unreal计算并应用反射效果。ScreenSpaceReflections使用Hi-Z缓冲区来加快光线行进相交的计算-针对较粗糙表面就使用更低mip的贴图,针对更光滑的表面则使用高mip的贴图从而实现更好的反射效果。
然后ReflectionEnvironmentAndSky将环境反射捕获考虑在内。环境反射探针是在游戏启动期间生成的,它们仅捕获静态几何体。每个探测器将捕获的反射存储在mipmapped立方体贴图中。
13、Atmosphere and Fog
请注意,这里还有另一个粒子传递GPUParticles_PostRenderOpaque。
14、Translucency
从这里开始,引擎最终开始处理半透明的物体(在我的案例中是2个雕塑和火的粒子效果)。
透明道具会受到局部和定向光,环境反射,雾气等的影响。默认情况下,渲染器使用高质量的着色器进行渲染透明道具。这个过程中会采样下面这些信息:
- 大气模拟预先计算的纹理,
- 烘焙的光照贴图数据,
- 半透明照明体积,其中包含来自方向照明和
- 局部的灯光信息和
- 反射探针立方体贴图,并使用它们来计算照明。
(译者注:原文中似乎不太对,我按照我的理解修改了一下。)
在此阶段,需要大量以前的渲染数据来进行半透明渲染,这就是为什么半透明昂贵的原因。
15、Distortion-失真
再次渲染透明道具和粒子(设置为折射),以写出具有失真矢量的全分辨率缓冲区,该失真矢量随后将用于计算折射。模板缓冲区在此过程中也处于活动状态,以标记需要折射的像素。
16、PostProcessing
在此阶段,渲染器将时间抗锯齿,运动模糊,自动曝光计算,光晕和色调映射等应用于主要渲染目标。
17、Wrap Up
在文章《如何虚幻渲染一帧》之后,我建立了自己的场景,并使用RenderDoc捕获了该帧,只是试图修改结果以供将来参考。我将继续回到这里,以添加有关渲染管道的更多见解。
qt 读取gif一帧_译:Unreal渲染一帧详解(Unreal Frame Breakdown)相关推荐
- java poi 模板填数据库,java使用POI读取excel模版并向固定表格里填写数据详解
java使用POI读取excel模版并向固定表格里填写数据详解:public class ExportExcelDemo { private HSSFWorkbook workbook = null; ...
- mbsfn子帧_区分小区内子帧状态的方法、装置以及系统_2008100004878_说明书_专利查询_专利网_钻瓜专利网...
技术领域 本发明涉及通信技术领域,尤其涉及一种区分小区内子帧状态的方法.装置以及系统. 背景技术 第三代组织伙伴计划(3GPP,Third Generation Partnership Project ...
- 中yeti不能加载_第二十章_类的加载过程详解
类的加载过程详解 概述 在 Java 中数据类型分为基本数据类型和引用数据类型.基本数据类型由虚拟机预先定义,引用数据类型则需要进行类的加载 按照 Java 虚拟机规范,从 Class 文件到加载到内 ...
- python处理nc数据_利用python如何处理nc数据详解
利用python如何处理nc数据详解 来源:中文源码网 浏览: 次 日期:2018年9月2日 [下载文档: 利用python如何处理nc数据详解.txt ] (友情提示:右键点上行txt ...
- ionic 修改组件默认样式_开源Magpie:组件库详解
开源项目专题系列(八)1.开源项目名称:magpie_fly2.github地址: https://github.com/wuba/magpie_fly 3.简介:magpie_fly 是58集体出品 ...
- 32通过tcp发送数组_【干货】TCP协议详解
关注我,你的眼睛会怀孕 为什么会有TCP/IP协议 在世界上各地,各种各样的电脑运行着各自不同的操作系统为大家服务,这些电脑在表达同一种信息的时候所使用的方法是千差万别.就好像圣经中上帝打乱了各地人的 ...
- SqlHelper帮助类_上(SQLServer数据库含Connection详解)
在操作数据库时,经常会用到自己封装的SqlHelper.这里主要对SQLServer数据库的Sqlhelper,主要用于在同一个连接中完成CRUD! 一.ADO.NET中的Connection详解: ...
- java判断颜色合法_判断颜色是否合法的正则表达式(详解)
判断颜色是否合法的正则表达式(详解) "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$"; 意思是:以#开头,后面是数字和a-f的字符(大写或小写),这个值是 ...
- python能处理nc文件吗_利用python如何处理nc数据详解
前言 这两天帮一个朋友处理了些 nc 数据,本以为很简单的事情,没想到里面涉及到了很多的细节和坑,无论是"知难行易"还是"知易行难"都不能充分的说明问题,还是& ...
最新文章
- void关键字的使用规则
- oracle中decode函数用法及应用
- 机房收费--组合查询
- 用Python写的一个monkeyrunner小工具(支持手机截图与定时截图,手机屏幕的显示)
- OO实现ALV TABLE 二:ALV显示的三种形式
- 消息模式在实际开发应用中的优势
- Java 将中缀表达式转换成后缀表达式
- oracle批量生成索引,ORACLE迁移时批量导出索引、存储过程,表结构等
- mysql 联合主键_深入理解Mysql索引底层数据结构与算法,背后的故事
- PrimeNG01 angular集成PrimeNG
- MongoDB 基本命令
- ASP.net MVC redis完整示例(含集合,哈希,sortedset)
- 基金前端代码和后端代码的区别 基金后端代码和基金前端代码区别
- android 计步器acc,基于加速度的门限检测计步算法设计
- 虚拟机中安装Synology
- 此计算机无法连接道家庭组,无法加入家庭组怎么办
- 阿里云大数据组件的基本介绍
- linux python3安装proton_深度deepin系统中通过Lutris(wine、proton)运行逆水寒的方法 ......
- 2345看图王如何关闭广告
- win10下设置超清晰壁纸
热门文章
- 根据图像连接数判别不同像素所处的位置
- jQuery Mobile中可折叠块collapsed的data-*选项
- 贺利坚老师汇编课程54笔记:CF进位标志CARRY FLAG
- 数据驱动和关键字驱动
- osmand中矢量数据地图绘制
- [转载] python中union函数_如何掌握Python union()方法及怎么用?
- [转载] python中*args 和 **kwargs区别
- [转载] 在Python中使用Matplotlib绘制常见图表
- 《Linux就该这么学》培训笔记_ch18_使用MariaDB数据库管理系统
- BZOJ.3261.最大异或和(可持久化Trie)