【OpenGL ES 3.x】- 着色语言GLSL

680 阅读6分钟

数据类型

着色语言有许多内置原生数据类型以及构建数据类型。这些数据类型可以分为标量、向量、矩阵、采样器、结构体以及数组等几类。

数据类型表示分类
浮点型float标量
布尔型bool标量
有符号整型int标量
无符号整型uint标量
矩阵型matrix矩阵
向量型vec2、vec3等向量

标量

标量由常见数据类型组成,不过多阐述。需要注意的是GLSL支持uint无符号整型。

向量

向量分量有两种使用方式:1、<向量名>.<分量名>;2、<向量名>[position]。 不但可以通过分量名称set-get,同时可以像数组一样通过下标获取分量。

向量类型说明
vec2包含2个浮点数的向量
vec4包含4个浮点数的向量
ivec2包含2个整数的向量
ivec4包含4个整数的向量
bec2包含2个布尔数的向量
bec4包含4个布尔数的向量
uvec2包含2个无符号整数的向量
uvec4包含4个无符号整数的向量

矩阵

矩阵主要运用在3D场景中的移位、旋转、缩放等变换。因此,OpenGL ES着色语言中也提供了对矩阵类型的支持也方便了开发快速创建矩阵。

矩阵类型说明
mat22x2浮点数矩阵
mat44x4浮点数矩阵
mat3x23x2浮点数矩阵
mat3x43x4浮点数矩阵
mat4x34x3浮点数矩阵

矩阵是按列顺序组织的,可以比作几个列向量组成。因此矩阵分量获取形式可以是二维数组的获取形式。

采样器

采样器类型说明
sampler2D用于访问浮点型二维纹理
sampler3D用于访问浮点型三维纹理
samplerCube用于访问浮点型的立方贴图纹理
samplerCubeShadow用于访问浮点型的立方阴影纹理
sampler2DShadow用于访问浮点型的二维贴图纹理
sampler2DArray用于访问浮点型的2D纹理数组
sampler2DArrayShadow用于访问浮点型的2D阴影纹理数组
isampler2D用于访问整型二维纹理
isampler3D用于访问整型三维纹理
isampler...用于访问整型系列的相关纹理(同上)
usampler...用于访问无符号整型系列的相关纹理(同上)

一般情况下采样器变量都用uniform限定符来修饰,采样器变量也可以用作函数的参数,但是作为函数参数时不可以使用out或inout修饰符来修饰。

结构体

着色语言结构体类似于C语言中的自定义结构体。

struct info{
    vec3 color;
    vec3 position;
    vec2 textureCoor;
}

数据类型使用

  1. 变量的声明及作用域与C++语法类似:分为局部变量与全局变量。
  2. 由于系统中有很多内建变量都是以“gl_”作为开头,开发者自定义变量不能以“gl_”作为开头。
  3. 向量和矩阵的初始化。
vec2 va = vec2(2.3,2.5);
vec3 vb = vec3(va,2.5);
vec4 vc1 = vec4(va,va); // 可以用两个vec2向量赋值
vec4 vc2 = vec4(2.0);// 向量每个分量都是2.0
vec3 vb2 = vec3(vc2);// 可以用vec4向量赋值,抛弃vec4最后一个分量
mat2 ma2 = mat2(0.1,0.2,0.3,0.4);
vec3 vb1 = vec3(2.1,2.5);
vec3 vb2 = vec3(2.2,2.5);
vec3 vb3 = vec3(2.3,2.5);
mat3 ma3 = mat3(vb1,vb2,vb3); //可以用三个vec3向量赋值
mat4 ma4 = mat4(vb1,vb2,vb3); 

vec2 ve2 = vec2(2.1,2.5);
mat4x2 ma4_2 = mat4x2(ve2,ve2,ve2,ve2); 
mat2x3 ma2_3 = mat2x3(ma4_2); //用ma4_2赋值,一列是三个分量,缺失的用0补齐,结果为[2.1,2.5,0,2.1,2.5,0]
mat2x2 ma2_2 = mat2x2(0.1); // 矩阵不填充所有值 结果为[0.1,0,0.1,0]

运算符

运算符与其他编程语言大同小异,没有特别语法糖设定,基本和常用编程语言一致。

运算符说明
()括号分组
++ --自加1 自减1
+ - ~ !一元运算符
+ - * / %加 减 乘 除 求余
<> <= >=关系运算符
&^ &&与 或 异或
?:选择
%= <<= >>= &= ^==赋值运算
[]数组下标
>> <<位运算
== !=等于 不等于
  1. 着色语言对于类型匹配要求严格,赋值表达式中的两个操作数类型必须完全相同。
  2. 类型转换只能通过构造函数实现。
float f = 1.0;
bool b = bool(f); // 非0是true,其他是false
float f1 = float(b); // true1.0false0.0
int i = int(f1); //	去掉小数部分
float f2 = 1; // 属于语法错误

限定符

限定符说明
const声明常量
in一般声明着色器输入变量
out一般声明着色器输出变量
uniform一般声明采样器或是一组顶点组成的单个3D物体所有顶点相同的量

插值限定符

插值(interpolation)限定符,其主要用于控制顶点着色器传递到片元着色器数据的插值方式。

插值限定符说明
smooth默认插值类型,以平滑方式插值得到片元输入变量
flat不对片元输入变量进行插值,直接使用特定值代替

layout限定符

layout限定符是从OpenGL ES 3.0开始出现的,其主要用于设置变量的存储索引(即引用)值。

<layout限定符> uniform
<layout限定符> <接口限定符> <变量声明>

场景应用如下

layout (location=0) in vec3 aPosition; // 输入变量的引用值为0
layout (location=2) in vec3 aColor;
layout (location=3) out vec3 aPosition2;
layout (location=4) out vec3 aColor2;

流程控制

流程控制大致上就是常见的条件判断、循环、中断等操作。基本关键字:if-else、switch、while、do-while、for、break、countinue。

GLSL内建变量

除了开发者自己使用变量外,在着色器中还有一些内置变量。这些内置变量不需要开发者声明即可使用。内建变量也分为输入量和输出量,输入量负责将渲染管线的固定信息传递给着色器,输出量负责着色器产生的信息传递给渲染管线。

内建输入变量

  1. gl_VertexID 顶点着色器的一个内建输入变量,类型为“highp int”
  2. gl_InstanceID 顶点着色器的一个内建输入变量,类型为“highp int”

内建输出变量

  1. gl_Position 顶点坐标,顶点着色器从渲染管线中获得原始的顶点位置数据,类型是vec4。
  2. gl_PointSize 点的大小,顶点着色器中可以计算一个点的大小(单位为像素)

这里只举例了个别内建变量,实际内建变量不只这些。另外除了内建变量外还有内建常量等,有兴趣可以通过GLSL语法书第七节[Built-in Variables]查找更多。

着色语言内置函数

内建变量、内建常量外,GLSL还提供了许多内置函数为开发带来方便。数学函数中常用方法基本都有:正弦函数、余弦函数、正切函数、角度转弧度、弧度转角度等。同样可通过第八节Built-in Functions查看更多。

编写GLSL代码

最后回到开篇时贴出的着色器代码注释内容。

顶点着色器vsh文件

aPosition是坐标输入量,使用的是vec3,在gl_Position内置变量赋值时通过vec4计算出16个顶点位置。 aColor是点颜色输入量,使用的是vec4,正好是16个点的颜色。 gl_PointSize是内置变量,设置点大小。

#version 300 es
layout (location = 0) in vec3 aPosition;  //顶点位置
layout (location = 1) in vec4 aColor;    //顶点颜色
out vec4 vColor;  //用于传递给片元着色器的变量

void main()
{
   gl_Position = vec4(aPosition,1); //根据总变换矩阵计算此次绘制此顶点位置
   vColor = aColor;//将接收的颜色传递给片元着色器
   gl_PointSize = 10.0;//点大小
}

片元着色器fsh文件

输入vColor给输出fragColor赋值,这里的fragColor就是内置变量gl_FragColor。 这里的vColor就是顶点着色器代码中输入的vColor。

#version 300 es
precision mediump float;
in  vec4 vColor; //接收从顶点着色器过来的参数
out vec4 fragColor;//输出到的片元颜色
void main()
{
   fragColor = vColor;//给此片元颜色值
}

参考