2.3 OpenGL着色器语言描述
2.3.1 使用GLSL构建着色器
变量的声明
GLSL是一种强类型的语言,所有变量都必须事先声明,并且要给出变量的类型。
GLSL中的基本数据类型:
类型 | 描述 |
---|---|
float | IEEE 32 位浮点数 |
double | IEEE 64 位浮点数 |
int | 有符号二进制补码的 32 位整数 |
uint | 无符号的 32 位整数 |
bool | 布尔值 |
变量的作用域
在任何函数定义之外声明的变量拥有全局作用域,因此对着色器程序中的所有函数都是可见的。
在一组大括号之内声明的变量,只能在大括号的范围内存在。
循环的迭代自变量,只能在循环体内起作用。
构造函数
向量的构造函数还可以用来截短或者加长一个向量。如果将一个较长的向量传递给一个较短向量的构造函数,那么向量将别自动取短到对应的长度。
vec4 color;
vec3 RGB = vec3 (color);
类似的,也可以使用同样的方式来加长一个向量。这也是唯一的一类构造函数,它的输入参数比变量的事迹分量数较少。
vec3 white = vec3(1.0); // white = (1.0, 1.0, 1.0);
vec4 translucent = vec4 (white, 0.5);
矩阵的构建方式于此相同,并且可以将它初始化为一个对角矩阵或者完全填充的矩阵。对于对角矩阵,只需要向构造函数传递一个值,矩阵的对角线元素就设置为这个值,其他元素全部设置为0,例如:
(4.0 0.0 0.0)
m = mat3(4.0) = (0.0 4.0 0.0)
(0.0 0.0 4.0)
矩阵的指定需要遵循列主序的原则,传入的数据将首先填充列,然后填充行。
mat3 M = mat3 (1.0, 2.0, 3.0,
4.0, 5.0, 6.0,
7.0, 8.0, 9.0);
得到的结果 (1.0 4.0 7.0)
----------------(2.0 5.0 8.0)
----------------(3.0 6.0 9.0)
向量分量的访问符
分量访问符 | 符号描述 |
---|---|
x, y, z, w | 与位置相关的分量 |
r, g, b, a | 与颜色相关的分量 |
s, t, p, q | 与纹理坐标相关的分量 |
2.3.2 存储限制符
类型修饰符 | 描述 |
---|---|
const | 将一个变量定义为只读形式,如果它初始化时用的是一个编译时常量,那么它本身也会成 为编译时常量 |
In | 设置这个变量为着色器阶段的输入变量 |
out | 设置这个变量为着色器阶段的输出变量 |
uniform | 设置这个变量为用户应用程序传递给着色器的数据,它对于给定的图元而言是一个常量 |
buffer | 设置应用程序共享的一块可读写的内存,这块内存与作为着色器中的存储缓存使用 |
shared | 设置变量是本地工作组中共享的。它只能用于计算着色器中 |
GLint glGenUniformLocation (GLuint program, const char* name);
返回着色器程序中uniform变量name对应的索引值。
当得到uniform变量的对应索引值之后,我们就可以通过glUniform*() 或者 glUniformMatrix*()系列函数来设置uniform变量的值了。
-
void glUniform {1234} {fdi ui} (GLint location, TYPE value);
-
void glUniform {1234} {fdi ui}v (GLint location, GLsizei count, const TYPE* values);
-
void glUniformMatrix {234} {fd} v (GLint location, GLsizei count, GLboolean transpose, const GLfloat* values);
-
void glUniformMatrix {2x3,2x4,3x2,3x4,4x2,4x3}{fd}v(GLint location, GLsizei count, GLboolean transpose, const GLfloat* values);
设置与location索引位置对应的uinform变量的值。
对于 glUniformMatrix {2x3,2x4,3x2,3x4,4x2,4x3} *()系列函数来说,可以从values中读入对应矩阵维度的数值构成矩阵。如果transpose设置为GL_TRUE,那么values中的数据是以行主序的顺序读入的,如果是GL_FALSE,那么values中的数据是以列主序的顺序读入的。
2.5 着色器编译
对于每个着色器对象:
1.创建一个着色器对象。
2.将着色器源代码编译为对象。
3.验证着色器的编译是否成功。
然后将多个着色器对象链接为一个着色器程序:
1.创建一个着色器程序。
2.将着色器对象关联到着色器程序。
3.链接着色器程序。
4.判断着色器的链接过程是否成功完成。
5.使用着色器来处理顶点和片元。
调用glCreateShader(GLenum type);
分配一个着色器对象,type必须是GL_VERTEX_SHADER、GL_FRAGMENT_SHADER、GL_TESS_CONTROL_SHADER、GL_TESS_EVALUATION_SHADER、GL_GEOMETRY_SHADER、或GL_COMPUTE_SHADER中的一个。返回指可能是一个非零的整数值,如果返回0说明发生了错误。
void glShaderSource (GLuint shader, GLsizei count, const GLchar** string, const GLint* length);
将着色器源代码关联到一个着色器对象shader上。
void glCompileShader (GLuint shader);
编译着色器的源代码。结果查询可以调用glGetShaderiv(),并且参数为GL_COMPILE_STATUS.返回的是编译过程的状态。如果返回为GL_TRUE,那么编译成功,下一步可以将对象链接到一个着色器程序中。如果返回失败,那么可以通过调取编译日志来判断错误的原因。glGetShaderInfoLog()函数会返回一个与具体实现相关的信息,用于描述编译时的错误。这个错误日志的大小可以通过调用glGetShaderiv()(带参数 GL_INFO_LENTH)来查询。
void glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, char* infoLog);
返回shader的最后编译效果。返回的日志信息是一个以NULL结尾的字符串,它保存在infoLog缓存中,长度为length个子浮窗。日志可以返回的最大值是通过bufSize来定义的。如果length设置为NULL,那么将不会返回infoLog的大小。
当创建并编译了所有必要的着色器对象之后,下一步就是链接它们以创建一个可执行的着色器程序。
GLuint glCreateProgram(void);
创建一个空的着色器程序。返回指是一个非零的整数,如果为0则说明发生了错误。
void glAttachShader(GLuint program, GLuint shader);
将着色器对象shader关联到着色器程序program上。
void glDetachShader(GLuint program, GLuint shader);
移除着色器对象shader与着色器程序program的关联。
void glLinkProgram (GLuint program);
处理所有与program关联的着色器对象来生成一个完整的着色器程序。
void glGetProgramInfoLog(GLuint program,GLsizei bufSize, GLsizei* length,char* infoLog);
返回最后一次program链接的日志信息。
void glUseProgram(GLuint program)
使用链接过的着色器程序program。如果program为零,那么所有当前使用的着色器都会被清除。
void glDeleteShader(GLuint shader);
删除着色器对象shader。如果shader当前已经链接到一个或者多个激活的着色器程序上,那么它将被标识为“可删除”,当对应的着色器程序不再使用的时候,就会自动删除这个对象。
void glDeleteProgram (GLuint program)
立即删除一个当前没有在任何环境下使用的着色器程序program.如果程序正在被某个环境使用,那么等他空闲时在删除。
最后,为了确保接口的完整性,还可以调用glIsShader()来判断某个着色器对象是否存在,或者通过glIsProgram()判断着色器程序是否存在。
GLboolean glIsShader(GLuint shader);
如果shader是一个通过glCreateShader()生成的着色器对象的名称,并且没有被删除,那么返回GL_TRUE,如果shader是零或者不是着色器对象名称的非零值,则返回GL_FALSE。
GLboolean glIsProgram(GLuint program);
如果program是一个通过glCreateProgram()生成的程序对象的名称,并且没有被删除,那么返回GL_TRUE,如果program是0或者不是着色器程序名称的非零值,则返回GL_FALSE。