GLSL 快速入门
官方文档:https://registry.khronos.org/OpenGL-Refpages/gl4/
Hello World
#version 450
void myFunction(in float inputValue, out int outputValue, inout float inAndOutValue) {
inputValue = 0.0;
outputValue = int(inAndOutValue + inputValue);
inAndOutValue = 3.0;
}
void main() {
float in1 = 10.5;
int out1 = 5;
float out2 = 10.0;
myFunction(in1, out1, out2);
}语言特征
- 类 C 语言,语法类似 C++
- 末尾有分号
; - 以
main()函数为主函数 - 注释
// ...和/* ... */
- 末尾有分号
- 基本数据类型
- 浮点型
float - 整型
int - 布尔型
true/false - 没有自动类型转换,类型必须匹配
- 浮点型
变量不能是关键字和保留字,不能以 gl_ 等开头。
GLSL 是强类型的语言,且赋值时变量的数据类型也要一致。
向量
GLSL 支持 2、3、4 维向量,根据分量的数据类型,我们还可以将多个向量合在一起:
vec3 v1 = vec3(1.0, 0.0, 0.5);
vec2 v2 = vec2(v1);
vec4 v3 = vec4(1.0);
vec4 v4b = vec4(v2, v3);
// (1.0, 0.0, 1.0, 1.0)向量默认都是 float 类型的。
向量分量的访问方式
通过分量属性访问:
v4.x, v4.y, v4.z, v4.w // 齐次坐标
v4.r, v4.g, v4.b, v4.a // 色值
v4.s, v4.t, v4.p, v4.q // 纹理坐标将分量的多个属性连在一起,可以获取多个向量:
vec4 v4 = vec4(1.0, 2.0, 3.0, 4.0);
v4.xy // (1.0, 2.0)
v4.yx // (2.0, 1.0)
v4.xw // (1.0, 4.0)通过分量索引访问:
v4[0], v4[1], v4[2], v4[3]用上面的方法访问到向量后,也可以用 = 号为向量赋值。
向量初始化时可以使用整数,但运算时一定要使用浮点数,否则会报错。
矩阵
GLSL 支持 2、3、4 维矩阵 mat2、mat3、mat4,矩阵中的元素都是浮点型。
GLSL 中的矩阵是列主序的,在建立矩阵的时候,其参数结构有很多种。
vec4 v4_1 = vec4(1, 2, 3, 4);
vec4 v4_2 = vec4(5, 6, 7, 8);
vec4 v4_3 = vec4(9, 10, 11, 12);
vec4 v4_4 = vec4(13, 14, 15, 16);
mat4 m = mat4(v4_1, v4_2, v4_3, v4_4);浮点+向量:
vec4 v4_1 = vec4(1, 5, 9, 13);
vec4 v4_2 = vec4(2, 6, 10, 14);
mat4 m = mat4(v4_1, v4_2, 3, 7, 11, 15, 4, 8, 12, 16);
/*
1, 5, 9, 13,
2, 6, 10, 14,
3, 7, 11, 15,
4, 8, 12, 16
*/单个浮点数
mat4 m = mat4(1);
/*
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
*/注:如矩阵中的参数数量大于 1,小于矩阵元素数量,会报错:
// 错误
mat4 m4 = mat4(1.0, 2.0);注意:矩阵和向量的索引下标只能是常数或者字面值,不能是其他变量。
部分 GLSL 支持逻辑异或 ^^ 。
向量与矩阵的运算
向量与向量的运算
distance(p0, p1); // 向量距离
dot(p0, p1); // 点积
cross(p0, p1); // 叉乘mat4 m = mat4(
1, 5, 9, 13,
2, 6, 10, 14,
3, 7, 11, 15,
4, 8, 12, 16
);
vec4 v = vec4(1, 2, 3, 4);由于 GLSL 是列主序的,故计算时相当于线性代数中的每个向量(或矩阵)的转置。
那么 m * v 的值为:
那么 v * m 的值为:
矩阵与矩阵的运算
加、减、除都是相同位置的元素进行运算,矩阵乘法满足乘法规则:
mat4 m = mat4(
2, 16, 8, 8,
4, 8, 8, 8,
8, 4, 8, 8,
16, 8, 8, 8
);
mat4 n = mat4(
1, 4, 1, 2,
2, 4, 2, 1,
4, 4, 1, 2,
8, 4, 2, 1
);m * n 的结果为:
计算结果即为:
mat4(
58, 68, 64, 64,
52, 80, 72, 72,
64, 116, 88, 88,
64, 176, 120, 120
)其他语法
结构体
struct Light {
vec4 color;
vec3 pos;
};GLSL 中的构造函数和 C++ 没有什么不同,唯一的区别就是构造函数传递的参数必须要全部使用,未用到的参数不要写到构造函数的参数列表中。
结构体默认有构造函数,其参数顺序和结构体中变量声明的顺序完全一致。
数组
GLSL 只支持一维数组,且长度只能是定值。
vec4 vs[2];
vs[0] = vec4(1, 2, 3, 4);
vs[1] = vec4(5, 6, 7, 8);控制流
支持 C/C++ 的 if / for / break / continue,此外还支持 discard 关键字,discard 直接终止这个着色器执行。
内置变量和函数
可参考官方文档。
abs()sin()cos()tan()atan()- ...
精度限定
mediump float size;
highp vec4 position;
lowp vec4 color;
precision mediump float;
precision highp int;基础类型
| 类型 | 说明 |
|---|---|
void | 空类型值 |
bool | 布尔类型 true 或 false |
int | 带符号的整数 |
float | 带符号的浮点数,标量 |
vec2, vec3, vec4 | 2、3、4 维浮点数向量 |
bvec2, bvec3, bvec4 | 2、3、4 维布尔向量 |
ivec2, ivec3, ivec4 | 2、3、4 维整数向量 |
mat2, mat3, mat4 | 2x2、3x3、4x4 浮点数矩阵 |
sampler2D | 2D 纹理(2D Texture) |
samplerCube | 盒纹理(Cube Mapped Texture) |
变量修饰符
| 修饰符 | 说明 |
|---|---|
<default> | (默认的)本地变量,可读可写 |
const | 声明变量或函数的参数为只读类型 |
attribute | 只能存在于 Vertex Shader 中,一般用于保存顶点或法线数据,它可以在数据缓冲区中读取数据 |
uniform | 在运行时 Shader 无法改变 uniform 变量,一般用来放置程序传递给 Shader 的变换矩阵、材质、光照参数等 |
varying | 主要负责在 Vertex 和 Fragment 之间传递变量 |
函数参数修饰符
| 修饰符 | 说明 |
|---|---|
in | (默认的)复制到函数中在函数中可读写 |
out | 返回时从函数中复制出来 |
inout | 复制到函数中并在返回时复制出来 |
宏指令
支持 C/C++ 预编译指令:
// 定义
#define
#undef
#ifdef
#ifndef
// 条件指令
#if
#elif
#else
#endif
// 其他常见指令
#error
#pragma
#extension
#version
#line