OpenGL分为两个部分:CPU上C++编写,GPU采用GLSL语言编写,后者就是着色器的编写方式。
基本数据类型
| 类型 | 描述 | 
|---|---|
| float | ieee 32 位浮点数 | 
| double | ieee 64 位浮点数 | 
| int | 有符号二进制补码的 32 位整数 | 
| uint | 无符号的32位整数 | 
| bool | 布尔值 | 
变量初始化
所有变量都必须在声明的同时进行初始化
| 1 | int i,nums = 1500; | 
构造函数
所有其他的数值转换都需要提供显示的转换构造函数
| 1 | float f = 10.0; | 
聚合类型
GLSL的向量与矩阵类型
| 基本数据类型 | 2D向量 | 3D向量 | 矩阵类型 | 
|---|---|---|---|
| float | vec2 | vec3 | .. | 
| double | dvec2 | dvec3 | .. | 
| int | ivec2 | ivec3 | .. | 
| uint | uvec2 | uvec3 | - | 
| bool | bvec2 | bvec3 | - | 
类型声明的变量的初始化:
| 1 | vec3 velocity = vec3(0.0, 2.0, 3.0); | 
类型之间的等价转换:
| 1 | ivec3 steps = ivec3(velocity); | 
向量之间的转换:
| 1 | # 减短 | 
注意⚠️:传入的数据将首先填充列,再填充行。
访问向量和矩阵中的元素
向量中的各个分量可以通过名称访问:
| 1 | float red = color.r; | 
或者通过一个从0开始的索引:
| 1 | float red = color[0]; | 
向量分量的访问符
| 分量访问符 | 符号描述 | 
|---|---|
| (X,Y,Z,W) | 与位置相关的分量 | 
| (r,g,b,a) | 与颜色相关的分量 | 
| (s,t,p,q) | 与纹理坐标相关的分量 | 
| 1 | vec3 luminance = color.rrr; # 输入颜色的红色分量来设置一个亮度值 | 
结构体
| 1 | struct Partical { | 
数组
数组的声明
| 1 | float coffee[3]; #有三个float元素的数组 | 
静态初始化一个数组的值
| 1 | float coffee[3] = float[3](2.00, 3.00, 5.23); | 
操作一个数组中的所有值
| 1 | for(int i = 0; i<coffee.length(); i++){ | 
获取列数
| 1 | mat3x4 m; | 
存储限制符
| 类型修饰符 | 描述 | 
|---|---|
| const | 将一个变量定义为只读形式。如果它初始化时用的是一个编译时变量,那么它本身也会成为编译时常量 | 
| in | 设置这个变量为着色器阶段的输入变量 | 
| out | 设置这个变量为着色器阶段的输出变量 | 
| uniform | 设置这个变量为用户应用程序传递给着色器的数据,它对于给定的图元而言是一个常量 | 
| buffer | 设置应用程序共享的一块可读写的内存。这块内存也作为着色器中的存储缓存使用 | 
| shared | 设置变量是本地工作组中共享的。它只能用于计算着色器中 | 
获取uniform变量的索引并且设置具体值
| 1 | GLint timeLoc; #着色器中的uniform变量time的索引 | 
算术操作符
| 优先级 | 操作符 | 可用类型 | 描述 | 
|---|---|---|---|
| 1 | () | - | 成组的操作 | 
| 2 | [] f() . ++、– | [数组、矩阵、向量] 函数 结构体 算术类型 | 数组的下标 函数的调用、构造函数 访问结构体的域变量/方法 后置递增/递减 | 
| 3 | ++、– +、- ~ ! | 算术类型 算术类型 整型 布尔型 | 前置递增/递减 | 
| 4 | *、/、% | ||
| 5 | +、- | ||
| 6 | <<、>> | ||
| 7 | <、>、<=、>= | ||
| 8 | ==、!= | ||
| 9 | & | ||
| 10 | ^ | ||
| 11 | ` | ` | |
| 12 | && | ||
| 13 | ^^ | ||
| 14 | ` | ` | |
| 15 | a?b:c | ||
| 16 | ==+=、-=*=、/=%=、<<=、>>=`&=、^=、 | =` | 任意 算术类型 算术类型 整型 整型 | 
| 17 | , | 任意 | 操作符序列 | 
操作符重载
流控制
| 语句 | 描述 | 
|---|---|
| break | 终止循环体的运行,并且继续执行循环体外的内容 | 
| continue | 终止循环体内当前迭代过程的执行,跳转到代码块开始部分并继续执行下一次迭代的内容 | 
| return | 从当前子例程返回,可以待会一个函数返回值 | 
| discard | 丢弃当前的片元,终止着色器的执行。discard语句只在片元着色器中有效 | 
函数
| 1 | float HornerEval(float coffee[10], float x); | 
计算的不变性
GLSL无法保证在不同的着色器中,两个完全相同的计算式会得到完全一样的结果。为了解决这个问题,需要用到invariant或者precise关键字。
invariant
将一个内置的输出变量声明为invariant,也可以声明一个用户自定义的变量为invariant:
| 1 | invariant gl_Position; | 
在调试过程中,可能需要将着色器中的所有可变量都设置为invariant。可以通过顶点着色器的预编译命令pragma来完成:
| 1 | #pragma STDGL invariant(all) | 
precise
precise限制符可以设置任何计算中的变量或者函数的返回值。它的作用是增加计算的可复用性
着色器的预处理器
预处理命令
控制常量与宏的定义
| 1 | #define | 
强制比那一起将text文字内容插入到着色器的信息日志中
| 1 | #error text | 
控制编译器的选项
| 1 | #pragma options | 
设置编译器支持特定GLSL扩展功能
| 1 | #extension options | 
设置当前使用的GLSL版本名称
| 1 | #version number | 
设置诊断行号
| 1 | #line options | 
宏定义
| 1 | #define NUM_ELEMENTS 10 | 
取消之前定义过的宏
| 1 | #undef LPos | 
数据快接口
着色器与应用程序之间,或者着色器个阶段之间共享的变量可以组织为变量块的形式。
| 1 | uniform b { //限定符可以为:uniform、in、out、buffer | 
或者
| 1 | uniform b { // | 
着色器的编译
创建着色器对象且通过链接生成可执行着色器程序的流程:(两部分)
(第一部分)对于每个着色器都会:
- 创建一个着色器对象。
- 将着色器源代码编译为对象。
- 验证着色器的比那一是否成功。
(第二部分)将多个着色器对象链接为一个着色器程序:
- 创建一个着色器程序。
- 将着色器对象关联到着色器程序。
- 链接着色器程序。
- 判断着色器的链接过程是否成功完成。
- 使用着色器来处理顶点和片元。
着色器子程序
| 1 | //第一步 |