本文由Arm公司的Roberto Lopez Mendez联合撰写。我们在Arm的合作伙伴最近将一个基于Unity内置渲染管线打造的项目移植到了通用渲染管线(URP)上,并希望与Unity社区分享他们的经验。
URP是我们预先打造好的可编程渲染管线(SRP)应用。它的工作流程十分便于美术创作,还可在大部分平台上呈现高度优化的图形。通过使用Shader Graph和VFX Graph等工具,没有编程经验的创作者也可以在URP上编写着色器和GPU渲染效果。
URP能帮助创作者实现性能与质量的平衡,管线的特色功能能将具备高质量图像的游戏和应用部署到多种移动设备上。如果想把项目从内置渲染管线移植到URP,你首先需要手动改写着色器。
在本文中,我们讨论了Arm项目向URP的移植,包括如何用自定义着色器实现基于本地Cubemap的动态软阴影。这篇文章涵盖了内置着色器到URP的自动转换、自定义着色器转换、LightMode标签的使用以及后处理。
如果想详细了解上述内容及更多使用技巧,请参阅我们的《高级 UNITY 创作者的通用渲染管线简介》。有经验的Unity开发者和技术美术师可以跟着我们的提示将项目从内置渲染管线移植到URP。
首先,将URP包添加到你的项目中。选择Window > Package Manager来打开Package Manager,从列表中安装Universal RP。要想升级着色器,找到Edit > Render Pipeline > Universal Render Pipeline > Upgrade Project Materials to URPipeline Materials选项。这一步能将Unity内置着色器自动转换成一套URP着色器。
您可以用这段教程及着色器升级文档来详细学习如何将内置着色器转换到URP。文档还以图表列出了内置着色器转换后对应的URP着色器。可以看到,几乎所有的旧版着色器都会转换成Universal Render Pipeline/Simple Lit着色器。
要想了解转换过程“底层”流程,一个快速的方法是查看旧版与URP着色器的源码。请先从Unity下载库中下载内置着色器。选择Windows或Mac平台,再选择Built-in shaders。解开文件,你会看到280多个着色器被分组在不同的文件夹里。
我们以Mobile-Diffuse着色器为例。该着色器将被转换为URP/Simple Lit着色器。你会发现很多URP着色器都来自URP GitHub仓库的Shader文件夹,以及Unity工程师Felipe Lira放在GitHub上的UniversalShaderExamples。
对于这个项目,Arm的开发者们决定使用URP Template中的示例场景。他们将“Drywall panel”游戏对象的着色器从URP/Lit改成了URP/Simple Lit,然后在Edit选项里打开了源码。
在比较URP SimpleLit.shader和Mobile-Diffuse.shader时,我们首先要注意到SubShader标签上的"RenderPipeline" = "UniversalPipeline"键值对:
SubShader的标签"RenderPipeline"将告诉Unity哪些渲染管线使用这个SubShader。值是"UniversalPipeline"表示Unity应在URP上使用这个SubShader。
在Render Pass(渲染通道)的代码里,你可以看到着色器的代码是使用HLSLPROGRAM/ENDHLSL宏来分隔的:
这些宏表明,原本的CG着色器编程语言(C for Graphics)已经被High-Level Shading Language(高级着色语言,HLSL)取代,尽管着色器的语法和功能基本相同。Unity的着色器文件使用ShaderLab语法来定义着色器属性、SubShader和Pass。对于URP来说,这些Pass里面的着色器代码是用HLSL写的。
大部分ShaderLab内容与内置渲染管线相比并无不同,但由于两个管线内部的光照生成流程有所不同,为内置渲染管线编写的ShaderLab着色器将自动被URP禁用。这表示URP着色器对光照的处理不同于内置渲染管线。
内置渲染管线会对每一束照射到物体上的光单独进行着色,而URP则在一个Pass里将所有光照和着色任务排列成组完成。这种差异使得URP会以不同的结构存储光照数据,并使用全新标准的着色库。
在渲染时,Unity会调取第一段受GPU支持的SubShader代码块。如果这段SubShader代码不包含"RenderPipeline" = "UniversalPipeline"标签,则着色器就不会运行于URP中。而Unity将继续运行下一个SubShader(如果有的话)。如果所有SubShader均不受GPU支持,则Unity会用大家熟悉的洋红色进行着色并标示错误。
一个SubShader可以包含多个Pass渲染通道,且每个通道都必须标记上一个具体的光照模式(LightMode)。由于URP使用的是单通道前向渲染器(Forward Renderer),管线只会将GPU支持的第一个"UniversalForward"通道用于渲染。
不过幸好,着色器升级程序能自动将内置着色器升级为URP着色器,帮你解决了繁杂的部分。那么自定义着色器又要怎样升级呢?
内置着色器函数是着色器编程的基础。它们不仅能节省你的时间,还能优化常见的运算。以这个include文件为例。它所包含的功能函数主要有平台特定功能、常见数学函数、纹理实用程序、纹理格式采样、深度编码/解码、空间变形、地形/笔刷高度图编码/解码以及其他实用程序。
你可以在《高级 UNITY 创作者的通用渲染管线简介》电子书的图表中查找内置和URP着色器上与变换相关的函数和预处理宏。
LightMode标签定义了Pass在光照管线上的作用。在内置渲染管线中,大多数与光照互动的着色器都会被写成十分详细的Surface Shader(表面着色器)。不过,自定义的内置着色器需要用LightMode标签来指明Pass在光照管线上的处理方法。
下表标出了内置渲染管线每个LightMode 标签对应的URP标签。部分旧版内置渲染管线的标签不受URP支持:
同时,有些URP中的标签也没有对应的内置渲染管线标签。
内置渲染管线(了解更多) | 描述 | URP(了解更多) |
---|---|---|
Always | 始终渲染;不应用光照 | 不支持 |
ForwardBase | 用于前向渲染;应用环境光、主方向光、顶点/SH光和光照贴图。 | UniversalForward |
ForwardAdd | 用于前向渲染;应用像素级累加光照,一条光照一条通道 | UniversalForward |
Deferred | 用于延迟渲染;渲染G-buffer | UniversalGBuffer |
ShadowCaster | 将对象的深度渲染到阴影贴图或深度纹理中 | ShadowCaster |
MovtionVectors | 用于计算每个对象的运动矢量 | MovtionVectors |
- | URP在前向渲染中使用的标签;该通道会渲染物体的几何外形并估算其对所有光照影响。 | UniversalForwardOnly |
- | URP在2D Renderer上使用的标签;该通道会渲染对象并估算其对2D光照影响 | Universal2D |
- | 该通道只将摄像机上的深度信息渲染成深度纹理。 | DepthOnly |
Meta | 该通道仅在Unity编辑器烘焙光照图时执行;Unity在构建运行版时会从着色器中删去该通道。 | Meta |
- | 使用该标签在渲染时加入一条额外通道;可用于前向和延迟渲染。 若通道没有LightMode标签,URP默认会应用该标签值。 | SRPDefaultUnlit |
URP目前不支持替换着色器。Dynamic Soft Shadows Based on Local Cubemaps项目原本是为内置渲染管线编写的。如下图所示,项目使用了简单的Custom/ctShadowMap着色器来替代棋子的原着色器进行渲染。
阴影摄像机被放在光照的位置,并借助着色器将棋子的外形渲染成一张纹理。这张纹理再被投射到棋盘上,产生棋子的影子。
不过,URP有一个替代方案。下方流程大致展示了棋子阴影的生成方法(详细信息请见Unity资源商店上的项目Readme文件):
后处理效果的种类取决于使用中的渲染管线。内置渲染管线的后处理与URP的后处理并不兼容。两者间的不同大致如下:
内置 | URP |
---|---|
默认不包含后处理方案;要想使用后处理效果,你需要使用Package Manager下载Post-Processing Version 2包,也称为Post-Processing Stack V2(PPv2)。 | 包括了自己的后处理方案,Unity会在创建URP模板项目时自动安装该方案;详见URP后处理文档。 要想利用后处理效果,请使用集成的体积系统,也叫做Post-Processing V3/PPv3。该系统包括了柔光、色差、景深、色彩调整、色调映射和晕影等效果。 |
Unity 2019.3的URP加入了一个集成的后处理堆栈,使管线有了若干的性能改进。更新后的堆栈还能支持摄像机运动模糊和体积框架等新效果。
然而,PPv3不支持自定义的后处理效果,所以2019.4 LTS仍支持PPv2以作为备选方案。若想在2019.4 LTS中使用自定义效果,请将后处理的Feature Set从集成方案设置为Post-Processing V2(如已安装)。
后处理在移动端会带来高能耗,这些效果将占用大量的帧时间。URP有几种对移动设备更友好的效果:
SRP的引入是Unity最大的转变之一,因为SRP支持用C#脚本安排和配置渲染 指令。URP的主要作用在于高效地创建可扩展、画面流畅的图形——既保证高端设备上的图形质量,又保证低端设备上的图形性能。
本文的表格只列举了部分可用的HLSL着色器函数、宏等。链接里的include文件还包含许多其他实用功能。你可以探索Unity安装文件夹的CG include等include文件,清楚地掌握HLSL的功能,并编写出自己的紧凑型着色器。
希望这些资源能让着色器的移植工作变得不那么艰巨。你可以随时前往URP论坛分享自己的经验或提问。
Is this article helpful for you?
Thank you for your feedback!