前言

  • 为什么要增加这个栏目?

由于个人目前主要学习Unity引擎,在引擎Shader的学习中,学了很多,但是不解的和不会的反而越来越多,借此机会自我总结一下,也为后续学习理清思路,该栏目将会随时间迭代更新。

  • 该栏目有哪些内容?

我个人目前的想法是从我的学习路线入手。Unity Shader入门精要 -> Catlike Coding -> 案例综合

  • 环境
    • 软件: Unity
    • 着色器语言: ShaderLab (CG/HLSL)

Unity Shader之渲染流水线

什么是渲染流水线?

由CPU、GPU共同完成,使用三维数据(顶点,法线等)将三维物体渲染成屏幕上的二维图像

流水线的概念早已学过,那么渲染流水线又是什么。首先要区别于GPU(硬件)流水线。

分为三个概念上的阶段,每个阶段又有子流水线。

  1. 应用阶段(application):开发者支配的阶段,输入场景、贴图、摄像机、光源等等;输出点、线、三角面等渲染图元。CPU上。

  2. 几何阶段(geometry): 这个阶段主要决定渲染哪些图元,以及将这些图元映射到二维平面上,最后输出包括屏幕上的着色,深度值,坐标等等到光栅器。

  3. 光栅化阶段(rasterization): 这个阶段同上一个阶段都是在GPU上进行,利用上一阶段的数据绘制出像素。先是逐顶点处理(对坐标,颜色逐顶点插值),然后是像素处理。

CPU和GPU之间的交互流程是怎样的?(Application)

之前提到渲染流水线是在CPU和GPU上进行。我们知道应用阶段在CPU上进行,下面是应用阶段CPU与GPU的交互流程。

  1. CPU控制数据从HDD(硬盘)中加载到显卡的显存(VRAM)中,数据包括位置、顶点着色、法线方向等。

  2. 通过CPU指定渲染状态,指导GPU使用哪个顶点/片元着色器,使用哪个光源属性、材质等。

  3. 准备好后CPU发起Draw Call命令,GPU根据渲染状态开始渲染。

上面三个阶段为应用阶段整个CPU和GPU交互流程。

什么是Draw Call

有一个命令缓冲区,用于CPU和GPU的并行处理。

Draw Call是其中的一道命令,用于发送渲染命令。下图中黄色框就是渲染命令Draw Call,红色是改变状态的命令。

尽量减少Draw Call

提交一次Draw Call需要提交数据,状态,命令等,如果一次能够绘制完,就不要分多次Draw Call.

类似于复制10MB的文件很快,但是复制10000个1KB的文件却很慢。

如何减少Draw Call是游戏优化中的一个重要命题。后续会以“优化”为主题详细讨论。

GPU流水线(Geometry&Rasterization)

已知几何与光栅化阶段在GPU上进行。以下为总览图。

几何阶段

  1. 顶点着色器(Vertex Shader) 负责顶点几何变换顶点着色
  1. 曲面细分(Tessellation Shader)、几何着色器(Geometry Shader)均为可选着色器,前者用来细分图元,后者用来执行图元着色操作和产生图元(增加)。

  2. 裁剪

位置分为完全在相机内,部分在相机内,完全不在相机内

裁剪用来处理部分在相机内的部分,将与相机交点替代相机外的部分。

需要注意的是顶点着色器是可编程的,但裁剪却是不可编程的,是硬件上的固定操作。

  1. 屏幕映射

输入三维坐标,映射到二维屏幕空间,z不做处理

光栅化阶段

  1. 三角形设置

已知顶点着色器不会记录点与点之间的关系

该过程用来得到三角形边界表达方式,计算像素覆盖情况。

  1. 三角形遍历(Triangle Traversal)

找到覆盖的像素,生成片元。

一个片元并不是真正意义上的像素,而是包含了很多状态的集合 这些状态用于计算每个像素的最终颜色

对三个顶点进行插值,然后三角形内部颜色由三点渐变(gradient)混合而成。

  1. 片元着色器(Fragment Shader)

DX中又称为像素着色器(Pixel Shader),不过片元不是真正意义上的像素,可编程

纹理采样,对三个顶点插值后,就可以得到片元的纹理坐标,仅可以影响单个片元,无法传递给邻居

  1. 逐片元操作(Per Fragment Operation)

主要进行修改颜色,深度缓冲,混合操作

为OpenGL的说法,DX具体较复杂

片元着色器执行后,进行模板测试(Stencil Test),再开始深度测试(Depth Test)

模板测试是根据比对模板值和reference value来判断(可设置)是否舍弃片元

深度测试则是比对深度,保留深度小的片元。

混合(Blend)操作,新渲染得到的颜色与颜色缓冲中的已有值做取舍。没有开启混合,计算得到什么,片元得到的就会是什么,也即不透明物体。如果开启了混合模式,会和原有颜色进行插值混合,表现为半透明。

现代GPU硬件特性,深度测试可以在片元着色器之前,但是不能同时。

参照深度测试 - 知乎 (zhihu.com)

补充

【显卡中除了图形处理单元GPU,还有显存(VRAM)】。

光栅化是一个过程,需要时间,为了得到连续图像,采样双缓冲机制(Double Buffering),Back Buffer计算新场景,Front Buffer显示当前场景,交换循环。

OpenGL、DX是CPU和GPU之间的桥梁,图形接口(api) (严格来说OpenGL不是图形api?,但是可以这么理解)

更详细地说

OpenGL没有提供着色器编译器,显卡驱动自己完成编译工作,GLSL的跨平台性在于编译结果依赖于硬件本身,而非局限于操作系统。不同显卡供应商的实现有所不同。

HLSL是针对微软产品的。不依赖于显卡驱动。

CG是跨平台的,根据不同平台翻译成中间语言,由于合作关系,和HLSL很像。但是可能无法发挥OpenGL新特性。

vv

提到了OpenGL和DX,就不得不提到Unity本身的跨平台性,两者坐标系不同,但是Unity自身提供翻转(开了抗锯齿+渲染到纹理就失效)

最后提一嘴,固定渲染管线由于对开发者极弱的开放性,渐渐退出历史舞台。