什么是管线(Pipeline)?
管线我们可以理解为流水线,流水线大家都懂,就是工厂里面生产东西的一整套流程。例如饮料厂要生产饮料,需要洗瓶子,倒饮料,加盖,包装等等,这一整套过程就是流水线。那么我们要把一个三维场景渲染成一幅二维的图像,同样需要一个先干嘛再干嘛然后干嘛最后干嘛的过程,这个过程或流水线,我们就称之为管线。
图形/渲染管线(Graphics/ Rendering Pipeline)
通过前面几篇的学习,我们知道了要把一个三维场景渲染成一幅二维的图像大致分为以下几个步骤:
- MVP变换和视口变换,把三维场景变的屏幕空间大小一样
- 光栅化,把物体离散成一个个的像素
- 深度缓存,根据每个像素做深度缓存
- 着色,根据着色频率的不同,不同的着色会在不同的时间点进行。
对于这一套流程,我们就可以称之为实时渲染管线,大致整理一下可以得到如下的流程图:
我们的MVP变换,视口变换实则是对物体表面也就是Mesh中的每个三角形的顶点进行变换,这步操作我们可以称之为 Vertex Processing,操作的内容都是顶点,即Vertex Stream。同时我们之前所说的高洛德着色就是在这里进行操作的,因为高洛德着色处理的就是顶点嘛。
顶点变换好后,我们自然可以通过这些顶点来获得我们想要的三角形,指定三个顶点即可连成一个三角形,即可得到所有的三角形面,即Triangle Stream,这步操作称之为 Triangle Processing。
然后我们就要把这些三角形进行光栅化,离散成一个个像素。在OpenGL中引入了 Fragment 的概念,我们可以理解为一个采样点所覆盖的区域即为一个Fragment,若我们对一个像素进行一次采样,那么Fragment就是一个像素,但是如果我们做MSAA操作,例如在一个像素选取四个点进行采样,那么这个像素就有四个Fragment。每个Fragment都会记录颜色,深度,透明度等信息,本文我们就简单的把一个Fragment当作是一个像素。因此在光栅化操作(Rasterization)中,我们得到的即是Fragment的集合(Fragment Stream)。
然后我们的深度缓存,以及冯氏着色都是针对每个Fragment进行处理的,这些相关操作我们称之为 Fragment Processing。在这里通过重心坐标我们就可以知道每个Fragment对应的颜色,从而得到每个像素对应的颜色。
这样,我们的一个管线就走完了,即可得到我们最终的结果,也就是一幅二维的图像。
当然了,上面的介绍仅仅只是一个大致的说明,实际上的渲染管线还要复杂的多,并且在不同的图形API里面,整个过程也是有所不同的,甚至相同的图形API里,随着版本的迭代,渲染管线也不断的更新。
Shader
上面所说的管线,都是在我们GPU里制定好的,但是在现代的GPU里,允许Vertex Processing和Fragment Processing这两部分是可编程的。也就是说我们可以通过自己写代码来控制它们是怎么着色的,而这部分代码就是Shader。
Shader本身是一个能在GPU上执行的模块,作用在Vertex Processing的我们称之为Vertex Shader,作用在Fragment Processing的我们称之为Fragment Shader。
从基本意义上来说,Shader只是一种把输入转化为输出的程序,也是一种非常独立的程序,因为它们之间不能相互通信;它们之间唯一的沟通只有通过输入和输出。Vertex Shader的输入即是顶点的属性,而它的输出往往会作为Fragment Shader的输入,Fragment Shader输出则是一个颜色值,代表每个像素的最终颜色。
我们可以使