【转载】Unity 渲染路径

351 阅读7分钟

原文

unity 2020 怎么写 shader 使其接受光照?_Unity渲染路径

正文

(基本上是翻译)

着色器(shaders)定义了物体本身的样子(材质属性),也定义了物体是如何应对光照的。 (本文主要讲 Unity Surface Shaders 背后的光照和渲染管线)

渲染路径(Rendering Paths)

Rending path 决定了光照是如何完成的,哪些 Passes 被使用。Shader 的 pass 通过 Pass Tags 来说明光照类型。

Shader的一个 Pass 块会引起一次对应 GameObject 的几何结构(一般是mesh)的渲染。也就是一个 pass 对应一次渲染。

Forward Rendering path(前向渲染路径)

Forward Rendering path 可能用一个或多个 pass 渲染每个物体,这由影响该物体的光源决定

在前向渲染中,在影响物体的光中,一些最亮的光(可以有至多 4 个点光源)使用 逐像素 的方式渲染。别的光使用以 逐顶点 的方式或 Spherical Harmonics lighting 的方式计算(SH Lighting 比较快,但只是一种近似)。

一个光(light)是否为逐像素光,取决于: 

  • 渲染模式(Render Mode)被设置为(Not Important)的光总是为 逐顶点 (per-vertex)光或者 SH 光。
  • 最亮的平行光(或者方向光,Directional Light)总是逐像素光(per-pixel)。 
  • 渲染模式(Render Mode)被设置为(Important)的光总是为逐像素光。
  • 若经过上面三步后,已确定的逐像素光数量仍小于 Quality Setting 中设置的 Pixel Light Count,则更多的光可以使用 per-pixel 方式渲染,根据光的 亮度递减顺序 决定。

每个物体按照如下方式渲染:

BasePass

Base Pass 中按 per-pixel 方式计算一个平行光(directional light),这个平行光可以有阴影,和所有逐顶点光和 SH 光。若 pass flag 中设置了 “OnlyDirectional”,则只计算一个平行光。这个 Pass 中可以使用 lightmaps、环境光、自发光(emissive lighting)等。

Additional Passes

除最亮的平行光外,别的每一个 per-pixel 光分别用一个 pass 计算,这些 passes 被称为 additional passes。这个 Pass 中的 per-pixel默认是没有阴影 的,除非使用 multi_compile_fwdadd_fullshadows

image.png

举例: 如上图,有一个物体(用图中的圆表示),它受到光 A-H 影响。假设光 A-H 有相同的颜色和强度,渲染模式都为 Auto ,则最亮的光 A-D 使用 per-pixel 模式渲染,最多 4 个。光源 D-G 使用 per-vertex 渲染,最终剩余的光(G-H)使用 SH 渲染,如下图,注意这几个光组是有重叠的(怎么实现的?)。

image.png

Deferred shading rendering path(延迟渲染路径)

在三维计算机图形学领域,deferred shading, 延迟渲染,是一种屏幕空间 shading 技术,最早由 Michael Deering 于 1988 年提出。之所以称之为 “延迟”(deferred)是因为在它的第一个 pass 中并 没有渲染 (shading)发生,而是推迟到第二个 pass 才进行渲染(shading)。 deferred shader 的第一个pass中,只是计算了一些渲染需要的一些数据,如:位置、法线、材质。这些数据被渲染到几何缓存 G-buffer(geometry buffer)中。然后,在 pixel shader(也即 fragment shader)中利用第一个 pass 中得到的 G-buffer 中的信息计算直接或间接光照信息。

优势

延迟渲染的 主要优势 是从光照(lighting)中解耦了几何(geometry)信息。只需要一个 pass 来计算几何信息。每一个光(light)只对它影响到的像素进行计算。因此可以在场景中添加大量光而不会造成显著的性能影响。

劣势

  • 延迟渲染的一个 主要缺点 是不能处理透明(transparency)(开启 Z-buffer 的场景都不能)。
  • 另一个 严重的问题 是不能使用多种材质(multiple materials),因为大量不同材质要求更多的数据存储在 G-buffer 中(G-buffer 中本来就有大量数据,占用大量存储空间了)。
  • 还有一个 重要的问题 是硬件反走样(hardware anti-aliasing)不能产生正确的结果,因为光照计算阶段(lighting stage)和几何计算阶段(geometric stage)是分开的(在不同 Pass 中完成),采样插值会得到错误的位置、法线、切线等信息。

Overview

在 Unity 中,当使用延迟渲染时,影响一个 GameObject 的光(light)的数量没有限制。并且所有的光是按 per-pixel 方式计算的,可以使用法线贴图(normal map)。另外,所有的光可以有 cookies 和阴影。

优点

由上文已知,在 deferred shading 中,光照的处理开销和光所影响的像素的数量成正比,而和光点亮的 GameObjects 的数量无关。因此,可以通过尽量减小光照的区域来提升性能。Deferred shading 具有高度一致且可预测的行为。由于每一个光都是按照 per-pixel 方式计算的,在大的三角形面片上不会有光照计算瑕疵。

缺点

和上文提到的一样,deferred shading 不能真正地支持反走样,不能处理半透明物体(这些是在 forward rendering 中处理的)。另外,在 deferred shading 中 Mesh Renderer 也不可以使用 Receive Shadows 标志,且 culling masks 也会受限制,最多可以使用 4 个 culling masks。

使用要求

  1. 要求显卡支持多个渲染目标(Multiple Render Targets, MRT),Shader Model 3.0 以上,且支持深度渲染纹理(Depth render textures)。大部分在 2006 年以后生产的 PC 上的显卡(以 GeForce 8xxx, Radeon X2400, Intel G45 等开头)支持 deferred shading。

  2. 运行 OpenGL ES3.0 以上的所有移动平台支持 deferred shading。

注意:  Deferred rendering 不支持 正交投影(Orthographic projection)。若相机投影模式设置为 Orthographic,则相机会使用 Forward rendering 。

性能注意事项

由于在延迟渲染中光的渲染开销和它 “点亮的” 像素个数成正比,和场景复杂度无关。因些小的点光源或聚光灯(spot lights)是非常廉价的,如果它们被别的物体遮挡的话,性价比就更高了。

当然,支持阴影的光会比不支持阴影的光开销大很多

实现细节

具有不支持 deferred shading 的 shaders 的物体在 deferred shading 完成后,按照 forward rendering 方式渲染。

G-buffer 中渲染目标(render targets, RT0-RT4)的默认布局如下。数据类型放在每个 render target 的各个通道中。通道放在括号中: 

  • RT0, ARGB32 格式: Diffuse color(RGB), occlusion(A).
  • RT1, ARGB32 格式: Specular color(RGB), roughness(A). 
  • RT2, ARGB2101010 格式: World space normal(RGB), unused(A).
  • RT3, ARGB2101010 (non-HDR)或者 ARGBHalf(HDR) 格式: Emission+lighting+lightmaps+reflection probes buffer. Depth+Stencil buffer.

因此 g-buffer 默认布局: 160 bits/pixel (non-HDR) 或者 192 bits/pixel(HDR).

若使用 Shadowmask 或者 Distance Shadowmask 模式用于混合光照(Mixed lighting),将会用到第 5 个渲染目标:

  • RT4, ARGB32 格式: Light occlusion values(RGBA).

因此,g-buffer 布局为: 192 bits/pixel (non-HDR) 或者 224 bits/pixel (HDR).

若硬件 不支持 五个并行渲染目标,则使用 shadowmasks 的对象将使用forward rendering path.

当相机 未使用 HDR 时,Emission+lighting buffer (RT3) 将被对数编码以提供更大的动态范围(相比于通常使用 ARGB32 纹理)。

注意 当相机使用 HDR rendering 时,不会有独立于 RT3 的渲染目标被创建;相反,使用的渲染目标是 RT3。

G-Buffer pass

G-buffer pass 只渲染每个对象一次。Diffuse colors, specular colors, surface smoothness, world space normal 和emission+ambient+reflections+lightmaps 被渲染进 g-buffer 纹理。g-buffer 纹理被设置为 全局 的 shader 属性,以便稍后由 shaders 来访问(CameraGBufferTexture0 .. CameraGBufferTexture3)。

Lighting pass

Lighting pass 根据 g-buffer 和 depth 计算光照。光照是在 屏幕空间 计算的,因此其处理时间 不依赖于场景复杂度。光照被添加到 emission buffer。

唯一可以使用的光照模型(lighting model)是 Standard

若想使用一个不同的模型,可以修改 lighting pass shader:把修改版的 Internal-DeferredShading.shader(来自 Built-in shaders)放到项目的 "Assets/Resources" 目录下,然后打开 Edit>Project Settings,点击 Graphics category,修改 "Deferred" 下拉列表为 "Custom Shader",最后把 Shader选 项设为自己定义的 shader。

(未完待续)

参考文献:

  1. Unity’s Rendering Pipeline
  2. ShaderLab: Pass
  3. en.wikipedia.org/wiki/Deferr…
  4. Spherical Harmonics lighting
  5. Deferred shading rendering path