GLSL语言基础

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zjz520yy/article/details/83114395

定义:GLSL释义叫做OpenGL着色器编程语言。是为图形计算量身定制的,它包含一些针对向量和矩阵操作的有用特性。

变量名字:变量名称的命名规范与C语言相同:可以使用字母,数字,以及下划线来组成变量的名字。但数字不能作为变量名称的第一个字符。此外由于在GLSL里连续的下划线是保留使用的,所以变量名称也不能包含连续的下划线。

变量的类型:常见类型如下:
1.基础数据类型:包含uint,int,float,double,bool。其中int可以隐式转换成uint;int或者uint隐式转换成float;以及int,uint,float隐式转换成double。其他基础数据类型的转换就只能通过构造函数转换了,如:

float value = 0.5;
int a = int(value);

2.聚合类型:包含有基础数据类型组合而成的向量和矩阵。
组合形式如图所示:
在这里插入图片描述
常见的操作如下所示:
初始化向量:可以指定每个分量值来初始化。代码如下:

vec3 velocity = vec3(0.0, 2.0, 3.0);

也可以使用构造函数来等价或者截取或者加长一个向量。代码如下:

// 等价向量初始化
vec3 velocity = vec3(0.0, 2.0, 3.0);
ivec3 steps = ivec3(velocity);

// 截取向量初始化
vec4 color;
vec3 RGB = vec3(color); // 只有RGB三个分量被截取出来

// 加长向量初始化
vec3 white = vec3(1.0); // white = (1.0, 1.0, 1.0)
vec4 translucent = vec4(white, 0.5);  // white新加一个0.5进行组合生成vec4变量

访问向量:可以通过分量的名称或者数组下标来访问向量。其中分量的名称通常含有与位置相关的分量(x, y, z, w),与颜色相关的分量(r, g, b, a)以及与纹理坐标相关的分量(s, t, p, q),在使用时可以灵活的取分量名称进行组合。代码如下:

// 只要保证取值的分量名存在,赋值的分量名存在且类型可以接收即可。
vec3 lumiance = color.rrr;

初始化矩阵:矩阵mat(mxn)中m代表列数,n代表行数,所以在初始化矩阵时,先初始化列再初始化行。可以传递一个数值来构建对角矩阵。代码如下:

// 由于矩阵大括号不好打出来,此处按照三列进行分割就可以得到具体形式
mat3 m = mat3(4.0) = (4.0, 0, 0,0, 4.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)

访问矩阵:通过数组下标进行访问矩阵。其中第一个下标代表取整列数据,第二个下标表示整列数据中指定的行数据。代码如下:

mat4 m = mat4(2.0);    // 初始化一个对角矩阵
vec4 zVec = m[2];     // 获取矩阵第三整列数据
float yScale = m[1][1];   // 获取矩阵第二整列数据中第二行数据,等价于m[1].y

3.结构体和数组:定义和使用方式与C语言类似,这里不再过多赘述。

存储限制符:用来改变数据类型的行为。常见的限制符如下所示:
1.const:用来设置变量为只读类型。与C语言使用规则一致。
2.out:用来定义着色器阶段的输出变量。可以是顶点着色器中的齐次坐标,也可以是片元着色器中的最终颜色。
3.in:用来定义着色器阶段的输入变量。可以是顶点着色器中的顶点属性,此时数据通过用户程序附加顶点属性的方式传递到变量上。设置代码如下所示:

// 顶点着色器
#version 450 core
layout (location = 0) in vec3 aPos;   // 位置变量的属性位置值为 0 
layout (location = 1) in vec3 aColor; // 颜色变量的属性位置值为 1

void main()
{
    gl_Position = vec4(aPos, 1.0);
}

// 用户程序附加顶点方式传递数据
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);   // 位置属性

glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3* sizeof(float)));
glEnableVertexAttribArray(1);  // 颜色属性

当然也可以是前一个着色器的输出变量,此时输出变量和当前着色器的输入变量不仅数据类型要相同,而且变量名也要相同。设置代码如下所示:

// 顶点着色器
#version 450 core
out vec4 vertexColor; // 为片段着色器指定一个颜色输出

void main()
{
    gl_Position = vec4(1.0);
    vertexColor = vec4(0.5, 0.0, 0.0, 1.0); // 把输出变量设置为暗红色
}

// 片段着色器
#version 330 core
out vec4 FragColor;

in vec4 vertexColor; // 从顶点着色器传来的输入变量(名称相同、类型相同)

void main()
{
    FragColor = vertexColor;
}

4.uniform:用来定义着色器之间共享的全局变量。这个uniform修饰的变量不能被着色器写入,只能被用户程序进行写入操作。在着色器程序进行链接着色器时会对所有着色器中的uniform变量生成一张索引列表。常用接口如下:
GLint glGetUniformLocation(GLuint program, const char* name):获取着色器程序中指定Uniform变量名字在索引列表中的索引值。
.program表示着色器程序标志。
.name表示uniform变量名字。

void glUniform{1234}{fdi ui}(GLint location, TYPE value);
void glUniform{1234}{fdi ui}v(GLint location, GLsizei count, GLboolean transpose, const TYPE* value);
void glUniformMatrix{234}{fd}v(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
void glUniformMatrix{2x3,2x4,3x2,3x4,4x2,4x3}{fd}v(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)

:设置指定索引值location处的uniform变量值。
.函数格式:这里的f表示float;d表示double;i表示int;ui表示uint;v表示vec;mxn表示m列n行。
.location表示Uniform变量位置。
.count表示用户数据个数。
.transpose表示矩阵中是否逆向取值,为GL_TRUE时表示取行列,否则表示取列行。
.value表示用户数据源。

5.buffer:用来定义着色器和用户程序之间共享的一片可读写内存缓存。
6.shared:用来在计算着色器中建立本地工作组共享的内存。

GLSL操作符:按照优先级降序排列的操作符如图所示:
在这里插入图片描述

GLSL流控制语句:常见的流控制语句如图所示:
在这里插入图片描述

GLSL参数限制符:GLSL中的函数与C++类似,但是参数没有引用和指针类型。常见的参数限制符如图所示:
在这里插入图片描述

计算的不变性:GLSL可以通过invariant或者precise限制符来确保着色器之间计算的不变性。使用方式如下:
1.invariant限制符:用来设置着色器中的输出变量。当不同着色器之间使用该变量的初始值相同以及该变量参与计算的表达式也相同时,那么得到的计算结果是保持一致的。在着色器中要将所有变量设置成invariant的话,只需要使用以下代码即可:

#pragma STDGL invariant(all)

2.precise限制符:用来设置任何变量和函数返回值的不变性。也就是说不管表达式中的计算变量怎么变化,最终表达式的计算结果是不变的。

预处理器命令:GLSL第一步解析的就是预处理器命令。常见命令如下:
1.#define,#undef:控制常量与宏的定义,与C语言的预处理器命令类似。
2.#if,#ifdef,#ifndef,#else,#elif,#endif:代码的条件编译。条件表达式中只可以使用整数表达式或者#define定义的值。
3.#error text:强迫编译器将text内容插入到着色器的信息日志中。
4.#pragma options:控制编译器的特定选项。常见的选项如下:

选项 描述
optimize 表示编译器优化选项,默认为开启。设置方式为:#pragma optimize(on或者off)
debug 表示编译器调试选择,默认为关闭。设置方式为:#pragma debug(on或者off)

5.#extension options:设置编译器支持特定GLSL扩展功能。设置方式代码如下:

// 操作某一具体扩展功能
#extension extension_name : <direcetve>
// 操作所有扩展功能
#extension all : <direcetve>

其中direcetve表示扩展命令修饰符。常见修饰符如下:

命令 描述
require 如果无法支持给定的扩展功能,或者被设置为all,则提示错误
enable 如果无法支持给定的扩展功能,则给出警告;如果被设置为all,则提示错误
warn 如果无法支持给定的扩展功能,或者在编译过程中使用了任何扩展,则给出警告
disable 禁止支持给定的扩展;如果被设置为all,则禁止所有的扩展。当在代码中涉及使用 禁止的扩展时,就会提示警告和错误

6.#version number:设置当前使用的GLSL版本名称。
7.#line options:设置诊断行号。

预定义宏:GLSL中的宏定义跟C语言中的宏定义类似,但是GLSL中的宏不支持字符串替换以及预编译连接符。常用的预定义宏如下:
1.LINE:行号,默认为已经处理的所有换行符的个数加一,也可以通过#line命令修改。
2.FILE:当前处理的源字符串编号。
3.VERSION:OpenGL着色语言的整数表示形式。

数据接口块:由于篇幅较多,以经另外写了篇博客来阐述。参考https://blog.csdn.net/zjz520yy/article/details/83662520

猜你喜欢

转载自blog.csdn.net/zjz520yy/article/details/83114395
今日推荐