2.3 着色器

着色器

着色器是使用一种叫GLSL的类C语言写成的。GLSL是为图形计算量身定制的,它包含一些针对向量和矩阵操作的有用特性。

着色器的开头总是要声明版本,接着是输入和输出变量、uniform和main函数。每个着色器的入口点都是main函数,在这个函数中我们处理所有的输入变量,并将结果输出到输出变量中。

一个典型的GLSL编写的着色器有下面结构。

#version version_number
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;
}

当谈到顶点着色器时,每个输入变量也叫做顶点属性,我们能声明的顶点属性是有上限的,由硬件来决定。

数据类型

基础类型

GLSL中包含C等其它语言大部分的默认基础数据类型:intfloatdoubleuintbool

GLSL也有两种容器类型,它们会在这个教程中使用很多,分别是向量(Vector)和矩阵(Matrix)

向量

GLSL中的向量是一个可以包含由1、2、3、4个分量的容器,分量的类型可以是前面默认基础类型中的其中一个。

类型 含义
vecn 包含n个float分量的默认向量
bvecn 包含n个bool分量的向量
ivecn 包含n个int分量的向量
uvecn 包含n个unsigned int分量的向量
dvecn 包含n个double分量的向量

向量的4个分量可以用.x, .y, .z.w来获取。

向量也允许一种灵活的分量选择方式,称为重组。

vec2 someVec;
vec4 differentVec = someVec.xyxx;
vec3 anotherVec = differentVec.zyw;
vec4 otherVec = someVec.xxxx + anotherVec.yxzy;

可以把向量当成一个参数传给不同的向量的构造函数,以减少参数的数量。

vec2 vect = vec2(0.5, 0.7);
vec4 result = vec4(vect, 0.0, 0.0);
vec4 otherResult = vec4(result.xyz, 1.0);

输入输出

每个着色器通过输入、输出来进行相互的数据交流和传递。输入输出变量的使用inout来标识。每个着色器使用这两个关键字设定输入和输出,只要一个输出变量与下一个着色器阶段的输入匹配,它就会传递下去。

顶点着色器可以从从顶点数据中直接接收输入。为了定义顶点数据该如何管理,我们使用location来指定输入变量,以便在CPU上配置顶点属性。

片段着色器需要一个vec4的颜色输出变量。

所以,如果我们打算从一个着色器向另一个着色器发送数据,我们必须在发送方着色器中声明一个输出,在接收方着色器中声明一个类似的输入。当类型和名字都一样的时候,OpenGL就会把两个变量链接到一起,它们之间就能发送数据了。

Uniform

Uniform是一种从CPU中的应用向GPU中的着色器发送数据的方式,但uniform和顶点属性有些不同。

uniform是全局的(Global)。全局意味着uniform变量必须在每个着色器程序对象中都是独一无二的,而且它可以被着色器程序的任意着色器在任意阶段访问。

无论你把uniform值设置成什么,uniform会一直保存它们的数据,直到它们被重置或更新。

查询uniform地址不要求你之前使用过着色器程序,但是更新一个uniform之前你必须先使用程序,因为它是在当前激活的着色器程序中设置uniform的。

猜你喜欢

转载自blog.csdn.net/NelsonCheung/article/details/109398342