从“1”开始3D编程
上QQ阅读APP看书,第一时间看更新

3.3 3D流水线

GL和Vulkan的流水线是类似的,如图3-3所示。

图3-3 3D流水线和顶点坐标、MVP、纹理坐标等的关系

用户输入的顶点、MVP矩阵、纹理以及纹理坐标,和流水线关联的部分主要如下。

(1)顶点着色器(vertex shader):根据用户输入的顶点和MVP信息,生成裁剪坐标gl_Position。

(2)顶点后期处理(vertex post processing):对顶点着色器输出的gl_Position进行透视除法,获得NDC坐标,如公式3-1所示。然后对NDC坐标进行视口变换,获得窗口坐标。

公式3-1 透视除法

在GPU里面,透视投影是在顶点着色器和顶点后期处理两个阶段分两步完成的。第一步在顶点着色器里面,将顶点坐标和透视投影矩阵相乘,得到裁剪坐标;第二步,在顶点后期处理阶段,通过固定管线的透视除法得到NDC坐标。

(3)光栅化:获得了图形的窗口顶点坐标后,要根据图形的窗口顶点生成相应的图形,譬如三角形,这个过程就是计算机图形学里面的扫描线算法。这个算法将三角形变成一条条的线,线上的点都是根据顶点插值生成的。每次插值生成线上的一个点,相应生成一个uv坐标,这个uv坐标对应一个片元,然后将这个uv坐标传递给片元着色器(fragment shader),片元着色器通过uv坐标对纹理进行采样,并对这个点进行着色。通常也用光栅化来代指基于透视投影和正交投影的3D编程模型,以和基于光线传播实现的光线追踪3D编程模型区分开。

(4)片元着色器(fragment shader):对扫描线生成的片元进行着色。颜色可以根据用户在输入顶点时指定的颜色插值生成,也可以来自用户提供的图片相应uv坐标位置的像素颜色。

通常用户代码会将uv坐标和顶点坐标以及顶点的颜色一起输入,如程序清单3-1所示。

程序清单3-1 uv坐标的一种输入方式(Vulkan)

上面的结构包含四个顶点信息,每个顶点信息包含:顶点坐标、uv坐标、顶点颜色。中间的uv坐标会和其他的顶点信息一起传递给顶点着色器和片元着色器。这里uv坐标就是{1.0f,1.0f},{0.0f,1.0f},{0.0f,0.0f},{1.0f,0.0f}。

相应的片元着色器如程序清单3-2所示。

程序清单3-2 片元着色器使用插值后的uv坐标

     layout (location=0)in vec2 inUV;

但是不能将inUV和用户顶点里面的四个uv坐标直接等同起来。inUV就是这四个顶点提供的uv坐标插值生成的点的集合。请注意,顶点着色器操作的是用户输入的顶点,而片元着色器操作的是通过顶点插值生成的所有点。

gl_Position和用户指定的顶点(vertex)是一一对应的(前提是顶点没有落在视景体外面)。或者说,物体空间的每一个顶点,在裁剪坐标空间都有一个对应的gl_Position。gl_Position经过透视除法后,得到NDC空间坐标。NDC空间的点,经过视口变换,得到窗口坐标。总的来说,每个顶点(vertex)都有一个对应的gl_Position,一个NDC空间的点。渲染(rasterization)阶段,对顶点坐标组装成的三角形应用扫描线(scanline)算法,插值得到顶点之外的填充区域的坐标点,并用片元着色器(fragment shader)对这些点进行着色(shading)。

所以顶点着色器是以顶点为单位进行的,一个三角形就是三个顶点,相应的顶点着色器会被调用三次。而片元着色器,是以片元(可以暂时理解为像素)为单位的,也就是最终显示在窗口上面的每个像素,都会执行一次片元着色器(没有多重采样的时候)。两者之间通过GPU的扫描线关联起来。