一、Unity中的渲染管线
渲染管线执行一系列操作来获取场景的内容,并将这些内容显示在屏幕上。概括来说,这些操作如下:剔除、渲染、后期处理。
1.剔除:它列出了需要渲染的对象,最好是那些对摄像机可见的w对象(视锥体剔除)和其他对象不遮挡的对象(遮挡剔除)。
2.渲染:第二个阶段渲染是指将这些对象绘制到基于像素的缓冲区中(通过正确的光照以及它们的一些属性)。
3.后处理:最后,可以在这些缓冲区上执行后期处理操作,例如,应用颜色分级、泛光和景深,从而生成发送到显示设备的最终输出帧。
首先要选择一个渲染管线。然后决定如何产生间接光照,并相应地选择一个全局光照系统。确保为您的项目适当地调整了所有全局光照设置之后,您可以继续添加光源、发光表面、反射探针、光照探针和光照探针代理体 (LPPV)。
Unity 提供以下渲染管线:
· 内置渲染管线 (Built-in) 是 Unity 的默认渲染管线。这是通用的渲染管线,其自定义选项有限。
· 通用渲染管线 (URP) 是一种可快速轻松自定义的可编程渲染管线,允许您在各种平台上创建优化的图形。
· 高清渲染管线 (HDRP) 是一种可编程渲染管线,可让您在高端平台上创建出色的高保真图形。
· 可编程渲染管线 (SRP) 可以使用 Unity 的可编程渲染管线 API 来创建自己的自定义渲染管线。
内置渲染管线Built-in
在 2018 年初之前,Unity 中只有一个渲染管线:内置渲染管线 (Built-In Render Pipeline)。此渲染管线提供了可选择的渲染路径:前向渲染路径和延迟渲染路径。
· 在使用(多通道)前向渲染路径时,场景中的所有对象都是按顺序渲染,根据影响每个对象的光源数量,可能在多个通道中渲染,因此当对象被多个光源照亮时,渲染成本会急剧增加。这种类型的渲染器通常提供各种各样的着色器,并且可以很轻松地处理透明度。
· 在使用延迟渲染路径时,所有(不透明)几何体首先渲染到缓冲区中,在其中存储有关材质的信息(颜色、镜面反射、光滑度等等)。在后一种通道(也就是“延迟”)中,每个像素按顺序着色:渲染时间将主要取决于影响每个像素的光源数量。对于透明对象以及某些包含复杂着色器的对象,仍然需要额外的前向渲染通道。当处理包含许多动态光源的场景时(例如具有人工光照的内部空间,或室外与室内光照相结合的项目),通常建议使用延迟渲染。需要注意的是,在移动设备上使用延迟渲染路径,缓冲区可能导致显存爆炸。
可编程渲染管线SRP
2018 年 1 月,Unity 推出了可编程渲染管线 (SRP),允许通过 C# 脚本来自定义渲染循环。这实际上是游戏引擎领域的一次小革命:用户终于无需使用像 C++ 这样的低级编程语言便可以个性化设置对象剔除、绘制和帧后期处理。
URP和HDRP是两个预先构建的SRP。
通用渲染管线URP
通用渲染管线 (URP) 是一种快速的单通道前向渲染器;它主要设计用于不支持计算着色器技术的低端设备,例如较早的智能手机、平板电脑和 XR 设备。但是,URP 还可为中端设备(如游戏主机和 PC)提供更高质量的图形性能,有时其性能成本低于内置渲染管线。URP 根据每个对象来剔除光线,并允许在单个通道中计算光照,与内置渲染管线相比,这会降低绘制调用次数。最后,URP 还提供 2D 渲染器,并规划了延迟渲染器。
高清渲染管线HDRP
高清渲染管线 (HDRP) 是一种混合延迟/前向瓦片/聚类渲染器。它提供了先进的渲染和着色功能,是专为要求逼真视觉的 PC 和高端游戏主机项目而设计。Tile是帧的一个小型二维方形像素部分,而Cluster则是摄像机视锥体中的一个三维体积。Tile和Cluster渲染技术都依赖于影响每个Tile和Cluster的光源的列表,然后可以用相应的已知光源列表在一个通道中计算其光照。不透明对象很可能使用Tile系统进行着色,而透明对象则依赖于Cluster系统。该渲染器的主要优点是,与内置渲染管线(延迟)相比,光照处理速度更快,带宽消耗也大大减少,因为内置渲染管线依赖于更慢的多通道光照积累。
二、GPU中的渲染管线
1.应用阶段Application Stage
这是一个由CPU主要负责的阶段,且完全由开发人员掌控。在这个阶段,CPU将决定递给GPU什么样的数据(譬如渲染目标场景中的灯光、场景的模型、摄像机的位置),有时候还会对这些数据进行处理(譬如只递给GPU可以被摄像机看见的元素,其他不可见的元素被剔除(culling)出去),并且告诉GPU这些数据的渲染状态(譬如纹理、材质、着色器等)。
2.几何阶段 Geometry Processing
Application结束后,GPU就拿到rendering primitives和一些相关指令、参数,开始了在GPU中的旅程。整个Geometry Processing阶段的目的是对输入的图元进行调整、修改、转换、增删等操作,在这整个阶段中,我们的处理对象是图元,输入的是图元,输出的还是图元。
图元数据:图元数据用来为后面的顶点着色器等阶段提供处理的数据。是渲染管线的数据主要来源。送入到渲染管线的数据包括顶点坐标、纹理坐标、顶点法线和顶点颜色等顶点属性。为了让OpenGL明白顶点数据构成的是什么图元,我们需要在绘制指令中传递相对应的图元信息。常见的图元包括:点(GL_POINTS)、线(GL_LINES)、线条(GL_LINE_STRIP)、三角面(GL_TRIANGLES)。
顶点着色器:顶点着色器主要功能是进行坐标变换。将输入的局部坐标变换到世界坐标、观察坐标和裁剪坐标。虽然我们也会在顶点着色器进行光照计算(称作高洛德着色),然后经过光栅化插值得到各个片段的颜色,但由于这种方法得到的光照比较不自然,所以一般在片段着色器进行光照计算。关于坐标变换以及着色方案的细节,我们会在后面详细介绍。
裁剪:在经过投影过程把顶点坐标转换到裁剪空间后,GPU就可以进行裁剪操作了。裁剪操作的目的就是把摄像机看不到的顶点剔除出去,使他们不被渲染到。得到顶点的归一化的设备坐标(Normalized Device Coordinates, NDC),经过齐次除法后,透视裁剪空间会变成一个x、y、z三个坐标都在[-1,1]区间内的立方体。对于正交裁剪空间就要简单得多,只需要把w分量去掉即可。
曲面细分:曲面细分是利用镶嵌化处理技术对三角面进行细分,以此来增加物体表面的三角面的数量,是渲染管线一个可选的阶段。它由外壳着色器(Hull Shader)、镶嵌器(Tessellator)和域着色器(Domain Shader)构成,其中外壳着色器和域着色器是可编程的,而镶嵌器是有硬件管理的。我们可以借助曲面细分的技术实现细节层次(Level-of-Detail)的机制,使得离摄像机越近的物体具有更加丰富的细节,而远离摄像机的物体具有较少的细节。
几何着色器:几何着色器也是渲染管线一个可选的阶段。我们知道,顶点着色器的输入是单个顶点(以及属性), 输出的是经过变换后的顶点。与顶点着色器不同,几何着色器的输入是完整的图元(比如,点),输出可以是一个或多个其他的图元(比如,三角面),或者不输出任何的图元。几何着色器的拿手好戏就是将输入的点或线扩展成多边形。下图展示了几何着色器如何将点扩展成多边形。
3.光栅化阶段
图元组装:图元组装将输入的顶点组装成指定的图元。图元组装阶段会进行裁剪和背面剔除相关的优化,以减少进入光栅化的图元的数量,加速渲染过程。在光栅化之前,还会进行屏幕映射的操作:透视除法和视口变换。
光栅化:经过图元组装以及屏幕映射阶段后,我们将物体坐标变换到了窗口坐标。光栅化是个离散化的过程,将3D连续的物体转化为离散屏幕像素点的过程。包括三角形组装和三角形遍历两个阶段。光栅化会确定图元所覆盖的片段,利用顶点属性插值得到片段的属性信息,然后送到片段着色器进行颜色计算,我们这里需要注意到片段是像素的候选者,只有通过后续的测试,片段才会成为最终显示的像素点。
片段着色器:片段着色器在DirectX中也成为像素着色器(Pixel Shader)。片段着色器用来决定屏幕上像素的最终颜色。在这个阶段会进行光照计算以及阴影处理,是渲染管线高级效果产生的地方。
测试混合阶段:管线的最后一个阶段是测试混合阶段。测试包括裁切测试、Alpha测试、模板测试和深度测试。没有经过测试的片段会被丢弃,不需要进行混合阶段;经过测试的片段会进入混合阶段。Alpha混合可以根据片段的alpha值进行混合,用来产生半透明的效果。测试混合阶段虽然不是可编程阶段,但是我们可以通过OpenGL或DirectX提供的接口进行配置,定制混合和测试的方式。