[TOC]
OpenGL ES着色语言虽然是基于C/C++基本语法的语言,但是其与C/C++相比较还是有很大不同的。例如,该语言不支持双精度浮点型(double)、字节型(byte)、短整型(short)、长整型(long),并且取消了C中的联合体(union)及枚举类型(enum)等特性。
1. 数据类型概述
与C语言类似,着色语言中有许多内建的原生数据类型以及构建数据类型,如浮点型(float)、布尔型(bool)、有符号整型(int)、无符号整型(uint)、矩阵型(matrix)以及向量型(vec2、vec3等)等。总体来说,这些数据类型可以分为标量、向量、矩阵、采样器、结构体以及数组等几类
-
标量
OpenGL ES3着色语言支持的标量类型有bool、int、uint与float
声明无符号整型(uint)字面常量时,需要在数字之后添加后缀u或U,否则该字面常量的类型为有符号整型
-
向量
OpenGL ES着色语言中,向量可以看作是用同样类型的标量组成的,其基本类型也分为bool、int、uint及float 四种。每个向量可以由2个、3个或者4个相同的标量组成.
向 量 类 型 | 说 明 |
---|---|
vec2 | 包含了2个浮点数的向量 |
bvec2 | 包含了2个布尔数的向量 |
vec3 | 包含了3个浮点数的向量 |
bvec3 | 包含了3个布尔数的向量 |
vec4 | 包含了4个浮点数的向量 |
bvec4 | 包含了4个布尔数的向量 |
ivec2 | 包含了2个整数的向量 |
uvec2 | 包含了2个无符号整数的向量 |
ivec3 | 包含了3个整数的向量 |
uvec3 | 包含了3个无符号整数的向量 |
ivec4 | 包含了4个整数的向量 |
uvec4 | 包含了4个无符号整数的向量 |
若向量是4维的,当看作颜色使用时,则可以使用的分量名为:r、g、b、a;
若向量是4维的,当看作位置使用时,则可以使用的分量名为:x、y、z、w;
若向量是4维的,当看作纹理坐标使用时,则可以使用的分量名为:s、t、p、q;
访问向量中的各个分量不但可以采用“.”加上不同的分量名,还可以将向量看作一个数组,用下标来进行访问
aColor.r=0.6; //给向量aColor的红色通道分量赋值
aColor.g=0.8; //给向量aColor的绿色通道分量赋值
aPosition.x=67.2; //给向量aPosition的X分量赋值
aPosition.z=48.3; //给向量aPosition的Z分量赋值
aTexCoor.s=0.65; //给向量aTexCoor的s分量赋值
aTexCoor.t=0.34; //给向量aTexCoor的t分量赋值
aColor[0]=0.6; //给向量aColor的红色通道分量赋值
aPosition[2]=48.3; //给向量aPosition的z轴分量赋值
aTexCoor[1]=0.34; //给向量aTexCoor的t分量赋值
-
矩阵
矩阵按尺寸分为2×2矩阵、2×3矩阵和2×4矩阵、3×2矩阵、3×3矩阵和3×4矩阵以及4×2矩阵、4×3矩阵和4×4矩阵,其中矩阵类型的第一个数字表示矩阵的列数,第二个数字表示矩阵的行数,具体情况如表4-2所列。
矩 阵 类 型 | 说 明 |
---|---|
mat2 | 2×2的浮点数矩阵 |
mat2×2 | 2×2的浮点数矩阵 |
mat3 | 3×3的浮点数矩阵 |
mat2×3 | 2×3的浮点数矩阵 |
mat4 | 4×4的浮点数矩阵 |
mat2×4 | 2×4的浮点数矩阵 |
mat3×2 | 3×2的浮点数矩阵 |
mat4×2 | 4×2的浮点数矩阵 |
mat3×3 | 3×3的浮点数矩阵 |
mat4×3 | 4×3的浮点数矩阵 |
mat3×4 | 3×4的浮点数矩阵 |
mat4×4 | 4×4的浮点数矩阵 |
OpenGL ES着色语言中,矩阵是按列顺序组织的,也就是一个矩阵可以看作由几个列向量组成。例如,mat3就可以看作由3个vec3组成。另外,mat2与mat2×2、mat3与mat3×3以及mat4与mat4×4是3组两两完全相同的类型,只是其类型的名称不同而已。
-
采样器
采样器是着色语言中不同于C语言的一种特殊的基本数据类型,其专门用来进行纹理采样的相关操作。一般情况下,一个采样器变量代表一幅或一套纹理贴图。
采样器类型 | 说 明 |
---|---|
sampler2D | 用于访问浮点型的二维纹理 |
isampler3D | 用于访问整型的三维纹理 |
sampler3D | 用于访问浮点型的三维纹理 |
isamplerCube | 用于访问整型的立方贴图纹理 |
samplerCube | 用于访问浮点型的立方贴图纹理 |
isampler2DArray | 用于访问整型的2D纹理数组 |
samplerCubeShadow | 用于访问浮点型的立方阴影纹理 |
usampler2D | 用于访问无符号整型的二维纹理 |
sampler2DShadow | 用于访问浮点型的二维阴影纹理 |
usampler3D | 用于访问无符号整型的三维纹理 |
sampler2DArray | 用于访问浮点型的2D纹理数组 |
usamplerCube | 用于访问无符号整型的立方贴图纹理 |
sampler2DArrayShadow | 用于访问浮点型的2D阴影纹理数组 |
usampler2DArray | 用于访问无符号整型的2D纹理数组 |
isampler2D | 用于访问整型的二维纹理 |
需要注意的是,与前面介绍的几类变量不同,采样器变量不能在着色器中进行初始化。一般情况下采样器变量都用uniform限定符来修饰,从宿主语言(如C++、Java)接收传递进着色器的值。此外,采样器变量也可以用作函数的参数,但是作为函数参数时不可以使用out或inout修饰符来修饰。
-
结构体
OpenGL ES着色语言还提供了类似于C语言中的用户自定义结构体,同样也是使用struct关键字进行声明,基本用法与C语言基本类似,不在此赘述了。
-
数组
在着色语言中,开发人员可以声明任何类型的数组。声明数组的方式主要有两种,具体如下所列。
(1). 在声明数组的同时,指定数组的大小:
vec3 position[20]; //声明了一个包含20个vec3的数组,索引从0开始
(2). 在声明数组并初始化的同时,可以不指定数组的大小,不支持动态长度数组
float x[]=float[2](1.0,2.0); //数组的长度为2
float y[]=float[](1.0,2.0,3.0); //数组的长度为3
OpenGL ES 3.0的着色语言只支持一维数组的使用,不支持二维以及更多维数组的使用。
2. 运算符
运 算 符 | 说 明 |
---|---|
() | 括号分组 |
[ ] | 数组下标 |
() | 函数调用和构造函数结构 |
. | 用于成员选择与混合 |
++ -- | 自加1与自减1后缀 |
++ -- | 自加1与自减1 前缀 |
+ - ~ ! | 一元运算符 |
* / % | 乘法、除法和取余 |
+ - | 加法与减法 |
<< >> | 逐位左移和右移 |
< > <= >= | 关系运算符 |
== != | 等于以及不等于 |
& | 逐位与 |
^ | 逐位异或 |
| | 逐位或 |
&& | 逻辑与 |
^^ | 逻辑异或 |
|| | 逻辑或 |
?: | 选择 |
= += -= *= /= | 赋值运算符 |
%= <<= >>= &= ^= |= | 赋值运算符 |
, | 按顺序排列 |
-
OpenGLES运算符的特殊操作
某些OpenGLES的运算符有不同于c语言的操作,下面简单介绍下。
- 通过运算符“.”进行混合选择操作
在运算符“.”之后列出一个向量中需要的各个分量的名称,就可以选择并重新排列这些分量。下面的代码片段说明了这个问题。
vec4 color= vec4(0.7,0.1,0.5,1.0); //声明一个vec4类型的向量color
vec3 temp=color.agb; //相当于获取到一个向量(1.0,0.1,0.5)赋值给temp
vec4 tempL=color.aabb; //相当于获取到一个向量(1.0,1.0,0.5,0.5)赋值给tempL
vec3 tempLL; //声明了一个3维向量tempLL
tempLL.grb=color.aab; //对向量tempLL的3个分量赋值
一次出现的各部分的分量名称必须是来自同一名称组。3个名称组分别为:xyzw、rgba、stpq
3. 构造函数
-
矩阵的构造函数
矩阵的构造函数共有3种基本形式。
- 如果矩阵的构造函数内只有一个标量值,那么矩阵的对角线上的分量都等于该值,其余值为0。
- 矩阵可以由许多向量构造而成。比如说,一个mat2矩阵可以由两个vec2构成。
- 矩阵还可以由大量的标量值构成,矩阵的分量由左向右依次被赋值。
vec2 d=vec2(1.0,2.0); //d的分量值分别为1.0、2.0
mat2 e=mat2(d,d); //e的第一列和第二列均为1.0、2.0
mat3 f=mat3(e); //将矩阵e放到矩阵f的左上角,右下角剩余对角线元素的值为1,其余为0
mat4x2 g=mat4x2(d,d,d,d); //声明一个mat4*2矩阵
mat2x3 h=mat2x3(g); //将矩阵g左上角的2*2个元素值赋值给h中的对应元素,h矩阵的最后一行为0,0
mat3 myMat3 = mat3(1.0, 0.0, 0.0, //矩阵myMat3第一列的值
0.0, 1.0, 0.0, //矩阵myMat3第二列的值
0.0, 1.0, 1.0); //矩阵myMat3第三列的值
OpenGL ES中矩阵元素的存储顺序以列为主,即矩阵由列向量组成。因此,当使用矩阵的构造函数时,矩阵的元素将会按照矩阵的列的顺序依次被参数赋值。这一点从上述代码片段的第5行有所体现
其他数据类型的构造函数和C语言一样,不再赘述。
类型转换
OpenGL ES着色语言没有提供类型的自动提升功能,并且对类型匹配的要求十分严格。赋值表达式中的两个操作数类型必须完全相同,另外调用函数时的形参以及实参的类型也必须完全相同。
同时OpenGL ES着色语言也没有提供数据类型的强制转换功能,只能使用构造函数来完成类型转换。
float f=1.0; //声明一个浮点数f并赋值
bool b=bool(f); //将浮点数转换成布尔类型,该构造函数将非0的数字转为true,0转为false
float f1=float(b); //将布尔值转变为浮点数,true转换为1.0,false转换为0.0
int c=int(f1); //将浮点数转换成有符号或者无符号整型,直接去掉小数部分
存储限定符
这些限定符中大部分只能用来修饰全局变量,主要的如下所列。
限 定 符 | 说 明 |
---|---|
const | 用于声明常量 |
in/centroid in | 一般用于声明着色器的输入变量,如顶点着色器中用来接收顶点位置、颜色等数据的变量,centroid in变量与插值类型有关 |
out/centroid out | 一般用来声明着色器的输出变量,如从顶点着色器向片元着色器传递的顶点位置等数据的变量,centroid out变量与插值类型有关 |
uniform | 一般用于对同一组顶点组成的单个3D物体中所有顶点都相同的量,如当前的光源位置 |
限定符在使用时应该放在变量类型之前,且使用in、uniform以及out限定符修饰的变量必须为全局变量。同时要注意的是,着色语言中没有默认限定符的概念,因此如果有需要,必须为全局变量明确指定需要的限定符。