对官方教程视频[官方培训]01-实时渲染基础上 | 陈拓 Epic的笔记

部分没听懂的地方就按自己的理解瞎写了

介绍

实时渲染(Real-Time Rendering,RTR)是指在计算机上快速生成图像的过程,它是计算机图形学中交互性最高的领域

图像出现在屏幕上,观众做出反应,这种反馈会影响接下来生成的内容。这种反应和渲染的循环以足够快的速度发生,以至于观众看不到单帧图像,而是沉浸在动态过程中

实时渲染不能做到完美

实时渲染在不渲染任何物体的时候性能是最高的

RTR流程的本质是管理性能损耗和画面质量的平衡

CPU和GPU

CPU和GPU负责处理渲染的不同部分,多数时候是同步的

CPU与GPU都有可能成为对方的瓶颈,需要知道工作负荷如何在两者间分配

渲染前的准备

前向渲染主要用在移动端、延迟渲染主要用在主机等硬件条件较好的平台上

渲染相关的三个线程:游戏线程(CPU)、计算线程(DRAW)、渲染线程(GPU)

游戏线程(CPU)

在开始渲染前,需要知道渲染的物体在什么位置

游戏线程执行所有逻辑计算和物体的变换

动画

模型或物体的位置物理

Al

生成或销毁,隐藏或显示

以及其他任何与物体位置变化相关的逻辑

计算线程(大部分在CPU)

至此,我们已经知道了各个物体处于什么位置

我们还需要知道哪些物体应该被渲染在画面中, 即只渲染可见的内容

这部分的工作大部分也是在CPU上计算的,但也有一部分是在GPU上计算

遮挡过程

建立一个可见物体的列表(逐物体,而不是逐三角形)

分为以下4个步骤处理

距离剔除

根据物体与相机的距离决定是否剔除(默认未开启)

设置单个物体的剔除距离, 距摄像机大于此距离则不渲染:

或者使用cull distance volume用体积进行多个物体批量设置

//在UE5测试发现距离剔除似乎对Nanite网格体不起作用

视锥剔除

根据物体是否在视锥内决定是否剔除

显示-高级中可以开启显示相机视锥

冻结当前渲染对象:

FreezeRendering

切换调试相机:

ToggleDebugCamera

可以看到视锥以外的物体没有被渲染:

解除冻结:

FreezeRendering 0

预计算可见性

通过Precomputed Visibility Volume将可见性结果提前计算好并储存下来

遮挡剔除

判断场景中物体是否被其他物体所遮挡,性能消耗最大,在最后才执行

遮挡过程性能提示

设置距离剔除

场景中大于1万个物体会对性能有较大影响

大部分情况下CPU是瓶颈,有时候也可能是GPU

遮挡在大型开放世界通常作用比较小

所有的物体都会被遮挡

大的物体很难被遮挡,因此在GPU渲染上可能需要消耗更多时间

渲染线程(GPU)

GPU现在已经知道了需要渲染的物体的列表及其位置信息,但是如果直接渲染,会有一些像素重复绘制,造成非常大的浪费

因此我们需要找出哪些模型应该先被渲染

Prepass/Early Z Pass机制

GPU驱动会在执行像素着色器前检查该点深度,提前跳过不符合条件的像素

如下图中,引擎会先获取一帧有场景深度信息的Buffer,将视野中可见的物体的深度写入深度buffer中,只写深度,不对物体进行复杂的光照计算,所以是轻量化操作,GPU在渲染时如果当前顶点的深度不是最前面的则跳过渲染,图中油桶被遮挡住的部分并没有进行渲染

Drawcall

Drawcall是指渲染时在特定pass中采用的单一处理过程

通常可以理解为绘制拥有相同属性的一组多边形

切换材质非常影响性能开销

在GPU渲染时,引擎会根据材质对物体进行排序,相同材质的会在一个批次里绘制

Drawcall 对性能有非常大的影响

每次GPU绘制完成后,需要从计算线程获取新的渲染指令,这里会有较大性能开销

Drawcall 数量对性能的影响比三角形数量要大的多

对比测试,下半部分中每个三角面都是不同的材质导致产生了大量Drawcall

查看运行统计数据的命令:

stat RHI

性能指标参考:

2000-3000: 合理

>=5000:略高

>=10000:也许会有性能问题

移动端在几百左右比较合适

Drawcall 相关的性能提示

Drawcall 数量相比多边形数量对性能的影响更大

引擎有一些 Drawcall的基础开销

为了降低 Drawcall,我们可以将模型进行合并,但也会带来副作用:

遮挡检测性能更差

计算碰撞性能更差

占用更多内存

一个较为常用的技术称为 Modular Meshes

也可以使用Instancing 降低 Drawcall

Level of Detail(LOD)和HLOD

通过Renderdoc插件可以检查每一帧的渲染详情

Shader

Shader是一小段在GPU上执行计算的代码

有许多不同类型的Shader: Vertex、Pixel、Compute、 Other

Shader运行非常高效

Vertex Shader(顶点着色器)

Vertex Shader是渲染过程的第一步,主要处理三件事情

将坐标从局部空间->世界空间->投影空间进行转换

处理顶点着色

应用世界坐标偏移 (World Position Offset,WPO)

WPO(世界坐标偏移)的一些例子:

水体表面

植被飘动

大量动画

由于数量巨大,不可能使用GPU单独去处理每个骨骼模型,每个角色其实都是静态模型,动画通过WPO实现

Shader 系统经过了高度优化,它是整个渲染过程的核心

CPU无法处理如此海量的数据

Vertex Shaders 并不直接修改模型,只是视觉上的效果

CPU无法察觉到Vertex Shaders对模型顶点数据的修改,因此物理和碰撞不会受任何影响

顶点着色器性能提示

动画越复杂性能越慢

顶点越多性能越慢

高精度的模型最好使用简单的Vertex shaders

对远距离的物体禁用顶点动画

Nanite

Nanite是虚幻引擎5新推出的虚拟几何体系统,采用新的内部网格体格式和渲染技术来渲染像素级别的细节以及海量物体对象,可以仅处理能观察到的细节,采用高度压缩的数据格式,并且支持高细节流送和自动LOD

几何体形状的复杂度提高了数个数量级,三角形和对象的实时渲染数量达到了前所未有的高度

帧预算不再会因为多边形数量、绘制调用和内存使用情况而受限

可以直接导入电影级品质的美术资源,例如ZBrush模型和摄影测量扫描数据

通过高模实现细节,而非通过烘培法线贴图来实现

自动处理LOD,不再需要手动设置

品质损失极少或没有损失,特别是在LOD发生过渡时

一般来说,能启用时应该尽量启用Nanite,虚幻引擎5中NaniteMesh渲染经过了高

度优化,通常可以更快渲染,占用的内存和磁盘空间也更少

具体而言,网格体如果满足以下条件,将很适合使用Nanite:

包含很多三角形,或屏幕上三角形非常小

场景中有很多实例

作为其他Nanite几何体的主要遮挡物

Nanite目前还不支持:

骨骼动画(Skeletal animation)

变形目标 (Morph Targets)

自定义深度或模板

半透明材质

材质的世界位置偏移 (World Position Offset in materials)

(做笔记的这会在最新的UE5.1版本已经支持WPO了,教程中演示用的还是4.27版本)

针对完整Nanite细节的光线追踪

支持光线追踪功能,但光线会与代理网格体(Nantie网格体的简化表现》交互,而不是具体的Nanite网格体

光栅化和G-Buffer

提供了变换数据、投影顶点以及必要的着色数据后,下一步是找到所有在这些三角形内部需要渲染的像素点,这个过程我们称为光栅化

光栅化按照Drawcall的顺序逐次调用

在远处观察一个有10 万面的模型,即使最终只占了画面中的一个像素,GPU仍然会处理这10万面的数据

由于硬件设计的原因,在计算一个像素的时候,同时还需要计算其周边2x2的像素

理想情况下我们希望屏幕上所有像素都只计算一次,但由于上文提到的原因,在顶点及边缘周围会不可避免的计算多次

光栅化和 OverShading 性能提示

多边形越密集,渲染的开销越大

从更远处观察物体,多边形的密度会增加

因此可以使用LOD的方法或远距离剔除减少这部分的开销

PixelShader越复杂,OverShading的开销也越大

非常细长的三角形也会造成比较严重的OverShading

G-Buffer

我们将物体表面信息储存到一系列的图像中,这些图像称为G-Buffer

G-Buffer可以用于合成各种信息,最终生成渲染输出

虚幻引擎会生成以下6张G-Buffer:

GBufferA.rgb = World Normal, with PerObjectGBufferData filling the alpha channel

GBufferB.rgba = Metallic, Specular, Roughness, ShadingModellD

GBufferC.rgb is the BaseColor with GBufferAO filling the alpha channel

GBufferD is dedicated to custom data. (PF_B8G8R8A8)

GBufferE is for precomputed shadow factors. (PF_B8G8R8A8)

GBufferF outputs WorldTangent in the rgb and anisotropy in the alpha channel

视口中可以通过"光照"-"缓冲显示"-"总览"查看各个生成的G-Buffer

G-Buffer 性能提示

G-Buffer会占用很多内存和带宽,因此对G-Buffer的数量是有限制的,如果需要

扩展G-Buffer需要考虑到这一点

纹理

纹理在导入时会被压缩,可以大大减少GPU显存占用

不同的平台有不同的压缩方式,Windows上通常使用BC算法

法线贴图使用了特殊的压缩方式,只保留了RG通道

(法线是归一化的, 即XYZ的平方和等于1, 所以只要知道其中两个就可以算出第三个)

Shader中对采样纹理的数量有限制

纹理的分辨率主要影响的是内存和带宽,而不是着色

为了减少锯齿以及加快渲染速度,我们需要使用Mipmap

1+%4+1/16+1/32+...=4/3=1.33,Mipmap会使图像占用大小增加为原来的1.3倍

Mipmap相关提示:

纹理的尺寸需要为2的幂次方,例如128x128,256x256,512x512...

长方形贴图长和宽都是是2的幂次方也是可以的

边长不是2的幂次方的贴图无法生成Mipmap和进行纹理流送

UI贴图可以不需要Mipmap

虚幻引擎默认使用DXT1压缩方式,压缩后纹理文件体积大约是原来大小的1/4

像素着色器和材质

像素着色器 (Pixelshader) 与顶点着色器(Vertex shader) 类似

在GPU上执行的程序,可以同时执行大量的简单计算,用于修改像素的颜色

对于渲染管线极为重要

像素着色器是材质系统的底层实现

同时也实现了光照、雾、后期等任何与效果相关的处理

像素着色器是以Shader Language书写的,在Windows平台上使用HLSL

不同平台使用不同的Shader Language,引擎会自动进行转换

PBR概念

材质管线很大一部分都基于PBR也就是基于物理的渲染 (Physical Based Rendering)

PBR使用Specular(高光度)/Metallic(金属度)/Roughness(粗糙度)来描述一种材质的属性

PBR是一种统一着色模型,可以通过修改参数表现很多不同的材质

UE中几乎所有的模型都是使用PBR模型进行渲染的

可以达到最快的效率

可预测性

基于G-Buffer的合成工作流限制

材质性能提示

每个材质的纹理采样器有最大数量限制 (16个),DX11可以使用共享采样器(最多可以使用128张纹理)

纹理尺寸过大会导致短暂的卡顿,但不会降低帧率

(纹理主要影响内存,对着色影响不是特别大)

像素着色器会对性能有非常大的影响,可以优化材质编辑器中的指令数(100~200)

屏幕输出的分辨率越大,复杂材质对性能的影响也越大

可视化查看材质着色器性能开销:

好文阅读

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。