GLSL语言
1. 引言
GLSL(OpenGL Shading Language)是一种用于编写着色器程序的编程语言,语法和C语言比较类似。
GLSL于2003年首次引入,作为OpenGL图形API的一部分,用于编写着色器程序。GLSL不仅在OpenGL中使用,还在其他图形API中得到了广泛应用,包括Vulkan和WebGL等。
2. 数据类型
2.1 基本数据类型
- 整数类型:int(32位整数)、uint(无符号32位整数)
- 布尔值:bool
- 浮点类型:float(单精度浮点数)、double(双精度浮点数)
GLSL没有指针、字符、字符串
//true/false bool bDone = false; int iValue = 42; uint uiValue = 32u; float fValue = 3.14159f;
2.2 矢量数据类型
矢量数据类型,用于同时处理多个数值。这些数据类型是浮点数或整数的数组,通常用于执行并行计算或者处理顶点和颜色等向量数据。
- vec2、vec3和vec4:表示2维、3维和4维浮点型向量。例如,vec3可以用来表示三维空间中的坐标。
- ivec2、ivec3和ivec4:表示2维、3维和4维整型向量。
- uvec2、uvec3和uvec4:表示2维、3维和4维无符号整型向量。
- bvec2、bvec3和bvec4:表示2维、3维和4维bool型向量。
vec4 v1; // 未初始化的向量
vec4 v2 = vec4(1,2,3,4); // 用四个单独的数值初始化
vec4 v3 = vec4(0,0,0,0); // 用四个0初始化
我们可以对向量进行各种操作,包括加法、减法、乘法等:
v1 = v2 + v3; // 向量加法
vec4 v4 = v1; // 向量复制
v1 += vec4(10,10,10,10); // 向量加法赋值
v1 *= 5; // 向量乘法
此外,我们还可以对向量的各个分量进行单独的操作:
v1.x = 3.0f; // 设置向量的x分量
v1.y = 4.0f; // 设置向量的y分量
v1.z = 5.0f; // 设置向量的z分量
v1.w = 1.0f; // 设置向量的w分量
我们还可以对向量的各个分量进行一起操作:
v1.xy = vec2(1,2);
v1.xyz = vec3(1,2,3);
// 获取向量的元素,可以通过r,g,b,a来获取向量中元素。
v2.r = 1.0f;
v2 = vec4(1.0f,1.0f,1.0f,1.0f);
// 获取向量元素,可以s,t,p,q来获取纹理坐标控制
v1.st=vec2(1.0,2.0);v1. st = v2. st:
// 不可以如下,xt不允许混合
v1.st = v2.xt
// 向量数据类型还可swizzle (调换)操作
// 将颜色数据RGB顺序转化BGR顺序
v1.bgra = v2.rgba;
// 向量的一次性所有分量操作
v1.x = v2.x + 5.0f;
v1.xyz = v2.xyz + vec3(5.0f,4.0f,1.0f);
2.3 矩阵类型
所有的矩阵类型只支持浮点数,不支持整数、bool类型。
mataxb, a = [2,3,4], b = [2,3,4], a是列数,b是行数
类型 | 描述 |
---|---|
mat2, mat2x2 | 两行两列 |
mat3, mat3x3 | 三行三列 |
mat4, mat4x4 | 四行四列 |
mat2x3 | 三行两列 |
mat2x4 | 四行两列 |
mat3x2 | 两行三列 |
mat3x4 | 四行三列 |
mat4x2 | 两行四列 |
mat4x3 | 三行四列 |
mat4 m1;
vec4 v2;
vec4 vOutPos ;
// 矩阵和向量相乘
m1 = mat4(
1.0,1.0,1.0,1.0,
1.0,1.0,1.0,1.0,
1.0,1.0,1.0,1.0,
1.0,1.0,1.0,1.0,
)
vOutPos = v2 * m1;
m1 = mat4(1.0f);
3. 变量和常见限定符
3.1 变量声明方式
在GLSL中,变量是用于存储和操作数据的关键元素。在声明变量时,需要指定其数据类型、名称以及可能的限定符:
数据类型 变量名;
- 输入变量:从外部(客户端/上一个阶段着色器传递的属性/Uniform等)。
- 输出变量:从任何着色器阶段进行写入的变量。
3.2 常见限定符
限定符是一种用于指定变量的作用域和存储方式的关键词。
限定符 | 描述 |
---|---|
<none> | 普通本地变量,外部不可见,不可访问 |
const | 编译常量,只读 |
in / varying | 前面着色器传过来的变量,通常用于在顶点着色器和片元着色器之间传递数据。它表明变量的值在这两个阶段之间插值 |
in / varying centroid | 前面着色器传过来的变量,使用质心差值 |
out / attribute | 传递到下一个着色器,或者在函数中指定返回值 |
out / attribute centroid | 传递到下一个着色器,使用质心差值 |
uniform | 声明全局变量,变量在整个着色器程序中都可见,通常用于将数据从应用程序传递给着色器 |
以下是一个使用限定符的变量声明示例:
uniform mat4 projectionMatrix; // 一个uniform矩阵
varying vec4 vertexColor; // 一个varying颜色向量
attribute vec3 position; // 一个attribute位置向量
3.3 内置变量
GLSL中有一些内置变量,它们在着色器程序中自动定义,用于与渲染管线和渲染过程进行通信。这些内置变量提供了关于顶点、片元和渲染状态的信息。以下是一些常见的GLSL内置变量:
- 顶点着色器内置变量:
gl_Position:
表示顶点的位置,通常是经过变换后的坐标。该变量必须在顶点着色器中设置,以确定绘制的位置。gl_PointSize:
表示点粒子的大小。通常在点粒子渲染时使用。- 片元着色器内置变量:
gl_FragColor:
表示片元(像素)的颜色。通过设置这个变量的值,您可以确定渲染到屏幕上的像素颜色。gl_FragCoord:
表示片元的屏幕坐标。可以用于执行特定的片元操作,例如根据屏幕坐标更改片元颜色。gl_FrontFacing:
表示片元是否在正面(front-facing)或背面(back-facing)多边形上。这对于执行不同的片元操作,例如剔除背面多边形,非常有用。gl_FragDepth:
表示片元的深度值。在需要自定义深度值的情况下,可以使用这个变量。- 通用内置变量:
gl_TextureCoord[]:
表示纹理坐标的数组,用于访问纹理。根据使用的纹理单元和纹理类型,可能会有多个 gl_TextureCoord。gl_ModelViewMatrix
和gl_ProjectionMatrix:
表示模型视图矩阵和投影矩阵。这些矩阵通常用于变换顶点位置。gl_NormalMatrix:
表示法线矩阵,用于法线的变换。gl_LightSource[]:
表示光源的属性,例如位置、颜色和强度。可以用于执行光照计算。gl_LightModel:
表示光照模型,包括环境光和局部光照。
4. GLSL编程基础
4.1 语法和语句
GLSL语句必须以分号(;)结尾,表示语句的结束。
float x = 5.0;
代码块通常使用大括号({})括起来,以表示作用域。
if (condition) { // 代码块 }
- 注释: GLSL支持C风格的注释,包括单行注释(//)和多行注释(/ /)。
- 大小写敏感: GLSL是大小写敏感的语言,因此变量名和函数名必须与其声明时的大小写完全匹配。
赋值语句: 用于给变量赋值,通常采用以下形式:
variable = expression;
条件语句: GLSL支持if语句,允许根据条件执行不同的代码块。
if (condition) { // 在条件为真时执行的代码 } else { // 在条件为假时执行的代码 }
循环: GLSL支持for和while循环,允许多次执行相同的代码块,直到满足特定条件为止。
for (int i = 0; i < 10; i++) { // 循循环执行的代码 } while (condition) { // 循环执行的代码 }
表达式: 表达式是由操作数和操作符组成的计算单元。GLSL支持各种数学运算,例如加法、减法、乘法和除法。例如:
float result = x + y * 2.0;
- 函数调用: GLSL支持函数调用,允许执行预定义的内置函数或自定义函数。例如:
float distance = length(vec3(x, y, z));
4.2 运算符和函数
4.2.1 运算符
GLSL支持各种数学和逻辑运算符,用于执行不同类型的运算。一些常见的运算符包括:
- 算术运算符:+(加法)、-(减法)、*(乘法)、/(除法)、%(取余)等。
- 关系运算符:<(小于)、>(大于)、<=(小于等于)、>=(大于等于)、==(等于)、!=(不等于)等。
- 逻辑运算符:&&(与)、||(或)、!(非)。
- 位运算符:&(按位与)、|(按位或)、^(按位异或)、<<(左移位)、>>(右移位)等。
- 赋值运算符:=、+=、-=、*=、/= 等。
4.2.2 函数
在GLSL中,函数的声明方式与其他编程语言类似,包括函数名称、参数列表和返回类型。以下是函数声明的基本格式:
返回类型 函数名称(参数类型 参数名称, 参数类型 参数名称, ...) {
// 函数体
return 返回值; // 可选
}
- 返回类型: 这是指定函数返回的数据类型,可以是整数、浮点数、向量、矩阵或其他数据类型。如果函数不返回任何值,可以使用void作为返回类型。
- 函数名称: 函数的名称是用来调用函数的标识符。
- 参数列表: 参数列表包括函数接受的参数,每个参数由参数类型和参数名称组成。参数列表用括号括起来,多个参数之间用逗号分隔。
- 函数体: 函数体包含函数执行的实际操作,即函数的主体。在函数体中,可以执行各种操作和计算。
- 返回值: 函数可以返回一个值,这个值的类型必须与函数的声明中的返回类型匹配。如果函数声明中的返回类型是void,则可以省略return语句。
函数声明示例:
float add(float a, float b) {
float result = a + b;
return result;
}
4.2.3 main函数
在GLSL编程中,每个着色器程序都需要包含一个名为 main 的特殊函数,这个函数充当着色器程序的入口点。 main 函数是由OpenGL或其他图形库调用的函数,用于执行特定的着色器阶段(例如,顶点着色器或片元着色器)。以下是 main 函数的一般形式:
void main() {
// 着色器程序的主要代码
}
4.2.4 内置函数
GLSL提供了广泛的内置函数,用于执行各种数学、向量和矩阵操作。一些常见的内置函数包括:
- 数学函数:sin()、cos()、tan()、sqrt()、exp()、log() 等,用于执行常见的数学运算。
- 向量函数:length()、normalize()、dot()、cross() 等,用于处理向量操作。
- 矩阵函数:mat4()、transpose()、inverse() 等,用于执行矩阵操作。
- 其它函数:GLSL还提供了各种其它函数,包括处理颜色、纹理、几何和辅助函数等。
这些内置函数帮助开发者执行各种复杂的数学和数据操作,从而实现图形渲染和通用计算任务。
5. GLSL代码文件形式
5.1 后缀名
GLSL并没有规定着色器语言后缀名,为了方便开发者理解,一般使用统一的后缀名对着色器进行区分。
比如一个项目中,可以使用以下后缀:
- vsh: 顶点着色器
- fsh: 片元着色器
5.2 文件中代码组织形式
一个着色器一般书写再同一个文件中,不能像c语言那样包含多个文件。
一个顶点着色器示例 some.vsh:
attribute vec4 position;
attribute vec2 textCoordinate;
uniform mat4 rotateMatrix;
varying lowp vec2 varyTextCoord;
void main(){
varyTextCoord = textCoordinate;
vec4 vPos = position;
vPos = vPos * rotateMatrix;
gl_Position = vPos;
}
一个片元着色器示例 some.fsh:
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main(){
gl_FragColor = texture2D(colorMap, varyTextCoord);
}
本文系作者 @何健源 原创发布在思维代码站点。未经许可,禁止转载。
暂无评论数据