着色器

GLSL

之前有提到过着色器是用一种类C的语言,当然其他图形API可能也有其专门的语言。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#version version_number //声明版本号
layout (location=0) in type in_variable_name;
in type in_variable_name;
in type in_variable_name;

out type out_variable_name;

uniform type uniform_name;

int main()
{
// 处理输入并进行一些图形操作
...
// 输出处理过的结果到输出变量
out_variable_name = weird_stuff_we_processed;
}
  • in/out:代表数据传入和传出,in是指接受外面传进来的数据,out是将数据传到外界,这个关键字之后在着色器之间的通信能用上,只要in和out关键字声明的变量名一样,便可以在两个着色器之间传递数据。

  • type:GLSL也有基本都类型:int、float、double、uint和bool。同时还有两种容器类型vector和Matrix。向量可以包含2、3和4个分量,向量用vecn来声明,n代表分量个数,同时还可以在vec前面加上b、i、u、d前缀代表不同的数据类型。

  • uniform:以uniform声明的变量可以看作是全局变量,也即是改变量在着色器程序中是唯一存在的,因此可以直接在CPU中向uniform变量传送数据。

    • glUniformnk(Location,…args):如何设置uniform的值,这个函数可以起到作用。和其他很多openGL的函数一样,由于openGL底层是C语言实现,所以函数不可以重载,因此就需要重新命名函数名,这里面n是代表需要几个数来填充uniform,例如一个vec3就需要三个数来填充,k则是代表数据的类型,这里和前面一样可以填b、i、u、d这几种基本类型。里面的参数Location表示的是uniform所在位置,这里需要使用glGetUniformLocation(programName,valueName)方法来进行查询。…args则是前面由n确定的参数。
  • layout(location=k):这里则是顶点的属性,里面的k表示的是属性的位置,这里要和glVertexAttribPointer中声明的属性位置相同。

片段差值

这里有一个有意思的现象,如果我们将三角形的每个顶点都添加一个颜色属性,然后将颜色属性从顶点着色器传递给片段着色器,让其作为最终颜色输出,这样我们会看到一个这样的画面:

colorfulTriangle.png

一个类型调色板的三角形。为什么通过确定三个顶点的颜色便可以使得中间的颜色出现渐变的效果?这就是片段差值。在之前的内容中说过,数据在管道中会经历光栅化的过程,所谓光栅化便是将图形分割成一个一个的像素块,在这个过程中,每个像素块会生成一个片段,这些片段也将会作为数据继续传递给片段着色器。片段中的数据当然也包括了颜色这一属性,落在三角形中间的像素确定颜色的方法大致就是根据像素点离三个顶点的距离得出不同的权重,然后再加权到三个顶点的颜色上,最后将颜色混合起来。这样一来,中间的颜色就会出现一种从顶点向中间过度的效果,这也叫做片段差值。