GLSL 全称为 OpenGL Shading Language ,是用来在OpenGL中编写着色器程序的语言。用GLSL编写的着色器程序是在图形卡的GPU (Graphic Processor Unit图形处理单元)上执行的,代替了固定的渲染管线的一部分,使渲染管线中不一样层次具备可编程性。好比:视图转换、投影转换、颜色混合等等。GLSL(GL Shading Language)的着色器代码分红2个部分:Vertex Shader(顶点着色器)和Fragment(片元着色器),有时还会有Geometry Shader(几何着色器)。
程序员
标识符其实就是程序员自定义的变量名、函数名等等。变量名能够由下划线、数组、字母组成,咱们能够随便用下划线、数组、字母定义变量名可是须要注意一下几点:编程
在GLSL中仅支持下列基础数据类型,须要注意的是与C语言相比GLSL中并无字符、字符串、指针这些类型。数组
Typebash |
Meaningapp |
void函数 |
for functions that do not return a valuepost |
boolui |
a conditional type, taking on values of true or falsespa |
intscala |
a signed integer |
float |
a single floating-point scalar |
vec2 |
a two component floating-point vector |
vec3 |
a three component floating-point vector |
vec4 |
a four component floating-point vector |
bvec2 |
a two component Boolean vector |
bvec3 |
a three component Boolean vector |
bvec4 |
a four component Boolean vector |
ivec2 |
a two component integer vector |
ivec3 |
a three component integer vector |
ivec4 |
a four component integer vector |
mat2 |
a 2×2 floating-point matrix |
mat3 |
a 3×3 floating-point matrix |
mat4 |
a 4×4 floating-point matrix |
mat2x2 |
same as a mat2 |
mat2x3 |
a floating-point matrix with 2 columns and 3 rows |
mat2x4 |
a floating-point matrix with 2 columns and 4 rows |
mat3x3 |
same as a mat3 |
mat3x4 |
a floating-point matrix with 3 columns and 4 rows |
mat4x2 |
a floating-point matrix with 4 columns and 2 rows |
mat4x3 |
a floating-point matrix with 4 columns and 3 rows |
mat4x4 |
same as a mat4 |
sampler1D |
a handle for accessing a 1D texture |
sampler2D |
a handle for accessing a 2D texture |
sampler3D |
a handle for accessing a 3D texture |
samplerCube |
a handle for accessing a cube mapped texture |
sampler1DShadow |
a handle for accessing a 1D depth texture with comparison |
sampler2DShadow |
a handle for accessing a 2D depth texture with comparison
|
除了以上这些基础数据类型,GLSL中还支持由以上这些类型组合而成的结构体、数组等复合数据类型
能够用struct 关键字将已定义的数据类型聚合到一块儿造成结构体,好比:
struct light {
float intensity;
vec3 position;
} lightVar;复制代码
结构体具体用法和C语言差很少这里就很少赘叙了;数组同样具体用法和C语言差很少,只不过在GLSL中不支持多维数组,也就是说数组的元素不能是数组。
GLSL中变量的定义能够在类型前面指定存储限定符,例如:
attribute vec4 position
uniform vec3 color = vec3(0.7, 0.7, 0.2)复制代码
GLSL中常见的存储限定符以下表:
限定符
|
意思 |
< none: default > |
默认的,可省略,这种状况下仅仅提供一个对相关处理器上内存的读写权限 |
const |
编译时常量,其值必须在声明时初始化,或只读的函数参数。 |
为每一个顶点数据链接顶点着色器和OpenGL。因此attribute表示只读的顶点数据,仅用在顶点着色器中。其数据来自当前的顶点状态或者顶点数组。它必须是全局范围声明的,不能再函数内部。attribute修饰的变量能够是浮点数类型的标量,向量,或者矩阵。不能够是数组或则结构体 |
|
uniform |
统一变量。在着色器执行期间统一变量的值是不变的,与const常量不一样的是,这个值在编译时期是未知的,是由着色器外部初始化的。统一变量在顶点着色器和片断着色器之间是共享的。它也只能在全局范围进行声明。 |
varying |
顶点着色器的输出。例如颜色或者纹理坐标,(插值后的数据)做为片断着色器的只读输入数据。必须是全局范围声明的全局变量。能够是浮点数类型的标量,向量,矩阵。不能是数组或者结构体。 |
centroid varying |
在没有多重采样的状况下,与varying是同样的意思。在多重采样时,centorid varying在光栅化的图形内部进行求值而不是在片断中心的固定位置求值。 |
限定符 |
说明 |
< none: default > |
默认使用 in 限定符 |
in |
in函数参数的默认限定符,传入形参的实际上是实参的一份拷贝.在函数中,修改in修饰的形参不会影响到实参变量自己 |
out |
out做用是向函数外部传递新值,out传递进来的参数是write-only的,就像是一个"坑位",坑位中的值须要函数给他赋予. 在函数中,修改out修饰的形参会影响到实参自己. |
inout |
inout 能够被理解为是一个带值的"坑位",及可读也可写,在函数中,修改inout修饰的形参会影响到实参自己. |
GLSL内部为咱们预先定义了一批具备特殊含义的变量,方便开发者使用,这些变量就是内置变量,在顶点着色器中有着以下的内置变量:
名称 |
类型 |
描述 |
gl_Color |
vec4 |
输入属性-表示顶点的主颜色 |
gl_SecondaryColor |
vec4 |
输入属性-表示顶点的辅助颜色 |
gl_Normal |
vec3 |
输入属性-表示顶点的法线值 |
gl_Vertex |
vec4 |
输入属性-表示物体空间的顶点位置 |
gl_MultiTexCoordn |
vec4 |
输入属性-表示顶点的第n个纹理的坐标 |
gl_FogCoord |
float |
输入属性-表示顶点的雾坐标 |
gl_Position |
vec4 |
输出属性-变换后的顶点的位置,用于后面的固定的裁剪等操做。全部的顶点着色器都必须写这个值。 |
gl_ClipVertex |
vec4 |
输出坐标,用于用户裁剪平面的裁剪 |
gl_PointSize |
float |
点的大小 |
gl_FrontColor |
vec4 |
正面的主颜色的varying输出 |
gl_BackColor |
vec4 |
背面主颜色的varying输出 |
gl_FrontSecondaryColor |
vec4 |
正面的辅助颜色的varying输出 |
gl_BackSecondaryColor |
vec4 |
背面的辅助颜色的varying输出 |
gl_TexCoord[] |
vec4 |
纹理坐标的数组varying输出 |
gl_FogFragCoord |
float |
雾坐标的varying输出 |
片元着色器中内置变量:
类型 |
描述 |
|
gl_Color |
包含主颜色的插值,只读输入
|
|
gl_SecondaryColor |
vec4 |
包含辅助颜色的插值,只读输入 |
gl_TexCoord[] |
vec4 |
包含纹理坐标数组的插值,只读输入 |
gl_FogFragCoord |
float |
包含雾坐标的插值,只读输入 |
gl_FragCoord |
vec4 |
窗口的x,y,z和1/w,只读输入 |
gl_FrontFacing |
bool |
只读输入,若是是窗口正面图元的一部分,则这个值为true |
gl_PointCoord |
vec2 |
点精灵的二维空间坐标范围在(0.0, 0.0)到(1.0, 1.0)之间,仅用于点图元和点精灵开启的状况下。 |
gl_FragData[] |
vec4 |
使用glDrawBuffers输出的数据数组。不能与gl_FragColor结合使用。 |
gl_FragColor |
vec4 |
输出的颜色用于随后的像素操做 |
gl_FragDepth |
float |
输出的深度用于随后的像素操做,若是这个值没有被写,则使用固定功能管线的深度值代替 |
操做符 |
描述 |
() |
用于表达式组合,函数调用,构造 |
[] |
数组下标,向量或矩阵的选择器 |
. |
结构体和向量的成员选择 |
++ – |
前缀或后缀的自增自减操做符 |
+ – ! |
一元操做符,表示正 负 逻辑非 |
* / |
乘 除操做符 |
+ - |
二元操做符 表示加 减操做 |
<> <= >= == != |
小于,大于,小于等于, 大于等于,等于,不等于 判断符 |
&& || ^^ |
逻辑与 ,或, 异或 |
?: |
条件判断符 |
= += –= *= /= |
赋值操做符 |
, |
表示序列 |
须要注意的是取地址符&和解引用的 * 操做在GLSL中是不存在的,由于GLSL不能直接操做地址。类型转换操做也是不容许的。 位操做符(&,|,^,~, <<, >> ,&=, |=, ^=, <<=, >>=)是GLSL保留的操做符,未来可能会被使用。还有求模操做(%,%=)也是保留的。
结构体的字段以及数组的长度都是经过点(.)语法来访问的,与c语言相似,对应结构体和数组仅一下几种操做是合法的:
field or method selector |
. |
相等判断 |
== != |
赋值 |
= |
索引访问[仅数组] |
[] |
须要注意的是相等判断和赋值运算都必须是两个类型同样,size相同的才能进行。
除了极少数例外,一般对于向量与矩阵的操做都等价于分别对其相应份量作出一样的操做。好比:
vec3 u,v;
float f;
v = u + f;复制代码
上面这段代码就等价于:
vec3 u,v;
float f;
v.x = u.x + f;
v.y = u.y + f;
v.z = u.z + f;复制代码
同理,代码:
vec3 v, u, w;
w = v + u;复制代码
等价于:
w.x = v.x + u.x;
w.y = v.y + u.y;
w.z = v.z + u.z;复制代码
其余的操做这里就不作多的叙述,你们能够参考线性代数或者3D数学。这里简单说一下向量份量的访问:
向量中单独的份量能够经过{x,y,z,w},{r,g,b,a}或者{s,t,p,q}的记法来表示。这些不一样的记法用于顶点坐标,颜色成分,纹理坐标。在份量访问中,不能够混合使用这些记法。其中{s,t,p,q}中的p替换了纹理的r坐标,由于与颜色r重复了。好比:
vec4 v4;
v4.rgba; // is a vec4 and the same as just using v4,
v4.rgb; // is a vec3,
v4.b; // is a float,
v4.xy; // is a vec2,
v4.xgba; // is illegal 复制代码
份量的顺序能够交换也能够重复:好比:
vec4 pos = vec4(1.0, 2.0, 3.0, 4.0);
vec4 swiz= pos.wzyx; // swiz = (4.0, 3.0, 2.0, 1.0)
vec4 dup = pos.xxyy; // dup = (1.0, 1.0, 2.0, 2.0)复制代码
这种表达方式一样能够用到表达式的左边,只是不容许重复:
vec4 pos = vec4(1.0, 2.0, 3.0, 4.0);
pos.xw = vec2(5.0, 6.0); // pos = (5.0, 2.0, 3.0, 6.0)
pos.wx = vec2(7.0, 8.0); // pos = (8.0, 2.0, 3.0, 7.0)
pos.xx = vec2(3.0, 4.0); // illegal - 'x' used twice
pos.xy = vec3(1.0, 2.0, 3.0); // illegal - mismatch between vec2 and vec3复制代码
对于矩阵能够当作是向量的数组,可使用数组下标语法访问矩阵的份量。 应用单个下标 到矩阵将矩阵视为列向量的数组,并选择一个单列,其类型为与矩阵大小相同的向量。 最左边的列是列0。而后第二个下标如先前为向量所定义,对列向量进行运算。 所以,两个下标选择了一列, 而后又选择了该列的一行。好比:
mat4 m;
m[1] = vec4(2.0); // sets the second column to all 2.0
m[0][0] = 1.0; // sets the upper left element to 1.0
m[2][3] = 2.0; // sets the 4th element of the third column to 2.0复制代码
条件控制:也就是常说的if else 语句,须要注意的是,if(条件)的条件只能是bool类型的,而且不能在if else中声明变量,变量必须声明在外面,好比:
vec4 color = unlitColor;
if (numLights > 0)
{
color = litColor;
}else{
color = unlitColor;
}复制代码
循环控制:与C语言相似支持for,while,do-while 三种写法,能够用contine跳出本次循环,用break跳出全部循环。
discard控制:片元着色器中有一种特殊的控制流成为discard。使用discard会退出片元着色器,不执行后面的片元着色操做,也不会写入帧缓冲区。
在每一个shader中必须有且只能有一个main函数。GLSL中的函数,必须是在全局范围定义和声明。不能在函数定义中声明或定义函数。函数必须有返回类型,参数是可选的。参数的修饰符(in, out, inout, const等)是可选的。
结构体和数组也能够做为函数的参数。若是是数组做为函数的参数,则必须制定其大小。在调用传参时,只传数组名就能够了。
另外须要注意一下几点:
最后这里咱们只是说了一下GLSL的一些基本语法,不过对于iOS开发者来讲其实已经基本足够了,若是想要深刻了解GLSL能够参考官方文档