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 | //第一步 |