基本特性
- GLSL中不支持指针和对象,不具有new运算符,创建对象用vec3(1.0, 1.0, 1.0)这种形式
- WebGL中GLSL只支持循环次数明确标定的for循环,支持continue和break
- 函数无返回值时必须声明为void类型,不支持递归,函数在使用前必须声明或定义
- 只支持一维数组,且声明数组时必须指定数组长度(常量或显式数字),函数中的数组参数必须声明长度
- 结构体只能包含属性,不能包含函数;数组和结构体可以互相包含
- 矩阵和向量之间可以直接使用原始操作符,相当于操作每个元素
- glsl不支持switch/case, 过多的if/else-if会影响shader的执行效率
- shader中的数据精度越高,计算量越大
- shader中的uniform,attribute变量,可以仅仅只是声明而不初始化和使用,此时,编译时它们会被删除。这时外部js获取它们的location就会失败;shader中使用的任何uniform,attribute变量必须外部传入,即便它们所在的分支永远不会被执行到。
- 顶点和片元着色器中相同名字的uniform变量,其类型和精度也必须一致。它们会在两个着色器中当成一个被共用。
类型转换内置函数
转换/函数/描述转换为整形数/int(float)/将浮点数的小数部分删去,转换为整形数(比如,将3.14转换为3)
转换为整形数/intl(bool)/true被转换为1,false被转换为0
转换为浮点数/float(int)/将整形数转换为浮点数(比如,将8转换为8.0)
转换为浮点数/float(bool)/true被转换为1.0,false被转换为0.0
转换为布尔值/bool(int)/0被转换为false,其他非0倍转换为true
转换为布尔值/0.0被转换为false,其他非0值被转换为true
矢量和矩阵类型
类型/GLEL ES 数据类型/描述矢量/vec2、vec3、vec4/具有2、3、4个浮点数元素的矢量
矢量/ivec、ivec3、ivec4/具有2、3、4个整形数元素的矢量
矢量/bvec、bvec3、bvec4/具有2、3、4个布尔值元素的矢量
矩阵/mat2、mat3、mat4/22、33、4*4的浮点数元素的矩阵(分别具有4、9、16个元素)
分量名
类别/描述x、y、z、w/用来获取顶点坐标分量
r、g、b、a/用来获取颜色分量
s、t、p、q/用来获取纹理坐标分量
由于矢量可用来存储顶点的坐标、颜色、纹理坐标,所以GLSL ES支持以上三种分量名称以增强程序的可读性。事实上,任何矢量的x、r或s分量都会返回第一个分量,y、g、t分量都返回第二个分量,等等。比如:
vec3 v3 = vec3(1.0, 2.0, 3.0) //将v3设置为(1.0, 2.0, 3.0)
float f;
f = v3.x; //设置f为1.0
f = v3.y //设置f为2.0
f = v3.z //设置f为3.0
f = v3.r; //设置f为1.0
f = v3.s; //设置f为1.0
将多个分量名共同置于点运算符后,就可以从矢量中同时抽取出多个分量。这个过程称为混合(swizzing)。下面的例子中,我们使用了x、y、z和w,其他的集合也有相同的效果:
vec2 v2;
v2 = v3.xy; //设v2为(1.0, 2.0)
v2 = v3.yz; //设v2位(2.0, 3.0) 可以省略任意分量
v2 = v3.xz; //设v2位(1.0, 3.0) 可以跳过任意分量
v2 = v3.yx; //设v2为(1.0, 1.0) 可以逆序
v2 = v3.xx; //设v2为(1.0, 1.0) 可以重复任意分量
vec3 v3a;
v3a = v3.zyx; //设v3a位(3.0, 2.0, 1.0),可以使用所有分量
[]运算符
矩阵中的元素任然是按照列主序读取的。与在javascript中一样,下表从0开始,所以通过[0]可以访问到矩阵中的第一列元素,[1]可以访问到第二列元素,[2]可以访问到第三列元素,如下所示:
此外,连续两个[]运算符可以访问某列的某个元素:
float m23 = m4[1][2]; //将m23设置为m4的第二列中的第三个元素(7.0)。
数组
GLSL ES只支持一维数组,而且数组对象不支持pop()和push()等操作,创建数组时也不需要使用new运算符。声明方式如下:
float floatArray[4]; // 声明含有4个浮点数元素的数组
vec4 vec4Array[2]; // 声明含有两个vec4对象的数组
数组的长度必须是大于0的整形常量表达式,如下定义:
1.整形字面量(0、1)
2.用const限定字修饰的全局变量或局部变量,不包含函数参数
因此,下面的代码将会出错:
int size = 4;
vec4 vec4Array[size]; //错误。如果第一行为const int size = 4;则不会报错
取样器(纹理)
我们必须通过取样器(sampler)类型变量访问纹理。有两种基本的取样器类型:sampler2D和samplerCube。取样器变量只能是uniform变量,或者需要访问纹理的函数,如texture2D()函数的参数。比如:
uniform smapler2D u_Sampler;
此外,唯一能赋给去取样变量的就是纹理单元编号,而且你必须使用WebGL方法gl.uniform1i()来进行赋值。例如:
gl.uniform1i(u_Sampler, 0) //将纹理单元编号0传给着色器
规范声明
如果函数定义在其调用之后,那么我们必须在进行调用之前先声明该函数的规范。规范声明不预先告诉WebGL系统函数的参数、参数类型、返回值类型等等。例如:
float luma(vec4); //规范声明
main(){
...
float brightness = luma(color); //luma()在定义之前就被调用了
}
float luma(vec4 color){
return 0.2126 * color.r + 0.7162 * color.g + 0.0722 * color.r;
}
内置函数
存储限定字
在GLSL ES中,我们经常使用attriute、varying和uniform限定字来修饰变量,如图所示:
此外,我们有时也会使用const限定字,它表示着色器中的某个变量使恒定的常量。几个存储限定自的使用分别如下:
1.Attribute变量
attribute变量只能出现在定点着色器中,只能被声明为全局变量,被用来表示逐顶点的信息。顶点着色器中能够容纳的attribute变量的最大数目与设备有关,你可以通过访问内置的全局常量获取该值。但是,支持WebGL环境都支持至少8个attribute变量。如下所示:
2.uniform变量
可以用在顶点着色器和片元着色器中,且必须是全局变量。uniform变量是只读的,它可以是除了数组或结构体之外的任意类型。如果顶点着色器和片元着色器中声明了同名的uniform变量,那么它就会被两种着色器共享。
3.varying变量
必须是全局变量,它的任务是从顶点着色器向片元着色器传输数据。我们必须在梁总着色器中声明同名、同类型的varying变量。它的类型只能是以下类型:float、vec2、vec3、vec4、mat2、 mat 3、mat4。
精度限定字
GLSL ES新引入了精度限定字,目的是帮助着色器程序提高运行效率,消减内存开支。使用精度限定字,你就能够精细地控制程序在效果和性能间的平衡。然而,精度限定字是可选的,如果你不确定,可以使用下面这个适中的默认值:
#ifdef GL_ES
precision mediump float;
#endif
如下所示,WebGL程序支持三种精度,其限定字分别为highp、mediump、lowp。

下面是声明变量精度的几个例子:
mediump float size; //中精度的浮点型变量
highp vec4 position; //具有高精度浮点型元素的vec4对象
lowp vec4 color; //具有低精度浮点型元素的vec4对象
为每个变量都声明精度很繁琐,我们也可以使用关键字precision来声明着色器的默认精度,并且这行代码必须放在顶点着色器或片元着色器的顶部,格式如下:
precision mediump float;
我们已经发使用精度限定字一般都只在片元着色器中使用,这是因为,除了片元着色器的float类型没有默认精度,其他类型都有默认精度。如下是数据类型的默认精度:
预处理指令
GLSL ES支持预处理指令。预处理指令用来在真正编译之前对代码进行预处理。都已#号开始。下面就是预定义float类型精度的预处理指令:
#ifdef GL_ES
precision mediump float;
#endif
下面是我们在GLSL ES中可能用到的三种预处理指令。
#if 条件表达式
If 如果条件比倒是为真,执行这里
#endif
#ifdef 谋宏
如果定义了某宏,执行这里
#endif
#ifndef 某宏
如果没有定义某宏,执行这里
#endif
可以使用一下指定进行宏定义:
#define 宏名 宏内容
可以使用undef 宏名,结束宏定义。例如:
#define NUM 100
#ifNUM == 100
如果宏NUM为100,执行这里
#else
否则,执行这里
#endif
预定义的内置宏有:
宏/描述GL_ES/在OpenGL ES2.0中定义为1
GL_FRAGEMENT_PRECISION_HIGH/片元着色器支持highp精度