GLSL 数据类型和限定符

GLSL的语言定义:
数据类型:
1、标量
float :声明一个单独的浮点数
int:声明一个单独的整数
uint  :声明一个无符号的整数
bool:声明一个单独的布尔数
不支持默认类型,必须在声明的时候指定类型。

2、矢量
vec2 :包含2个浮点数的矢量
vec3 :包含3个浮点数的矢量
vec4 :包含4个浮点数的矢量

ivec2 :包含2个整数的矢量
ivec3 :包含3个整数的矢量
ivec4 :包含4个整数的矢量

uvec2 :包含2个无符号整数的矢量
uvec3 :包含3个无符号整数的矢量
uvec4 :包含4个无符号整数的矢量

bvec2 :包含2个布尔数的矢量
bvec3 :包含3个布尔数的矢量
bvec4 :包含4个布尔数的矢量

内置的矢量可以很方便的存储和操作颜色、位置和纹理坐标等。
矢量的特殊性质包括可以通过字段选择(就像是用结构一样)或者作为数组来访问各个分量。
例如:
如果position是一个vec3,那么可以认为它是矢量(x, y, z),而position.x就将选择矢量
的第一部分。
总之,可以使用下面的名称来选择矢量的各个部分:
x、y、z、w将矢量看作一个位置或者是方向
r、g、b、a将矢量看作一种颜色
s、t、p、q将矢量看作一个纹理坐标
对于将矢量指定为一种颜色、一个位置、一个坐标等,并没有明确的方法,提供这些分
量选择名称只是为了在着色器程序中具有更好的可读性。从语言的角度来说,这些都是
矢量。

3、矩阵
对于浮点数矩阵,可以使用内置类型。其大小有 2*2 、 3*3 、 4*4 三种。
mat22*2 的浮点数矩阵
mat33*3 的浮点数矩阵
mat44*4 的浮点数矩阵

可以将矩阵作为矢量的数组来访问,也就是说,如果一个transform是一个mat4,那么
transform[2]就是transform的第三列。transform[2]的最终类型就是vec4。因为矢量是
可以作为数组来对待的,所以transform[3][1]是构成transform矩阵的第 4 列的第 2 个
分量。看起来好像矩阵transform是一个二维数组一样。只需要记住,transform的第一个
索引选定的是列而不是行,第二高峰索引选定的才是行。
            x,  y,  z,  w
mat4 transform={ 1,  0,  0,  0,

            0,  1,  0,  0,

                        0,  0,  1,  0,

          0,  0,  0,  0}
在OpenGL中,矩阵式按列顺序组织的。j矩阵的乘法也是左乘。如下:
[ m1 m5 m9  m13 ] [x] [ m1*x + m5*x + m9*x  + m13*x ]
[ m2 m6 m10 m14 ] * [y] = [ m2*y + m6*y + m10*y + m14*y ]
[ m3 m7 m11 m15 ]   [z]  [ m3*z + m7*z + m11*z + m15*z ]
[ m4 m8 m12 m16 ]   [1] [ m4*1 + m8*1 + m12*1 + m16*1 ]

Example:
[ 1 0 0 0 ] [1] [ 1*1 + 0*1 + 0*1 + 0*1 ] [1 + 0 + 0 + 0] [1]
[ 0 1 0 0 ] [2] = [ 0*2 + 1*2 + 0*2 + 0*2 ] = [0 + 2 + 0 + 0] = [2]
[ 0 0 1 0 ] [3]  [ 0*3 + 0*3 + 1*3 + 0*3 ]  [0 + 0 + 3 + 0] [3]
[ 0 0 0 1 ] [1]  [ 0*1 + 0*1 + 0*1 + 1*1 ]  [0 + 0 + 0 + 1] [1]

4、取样器
纹理查找需要指定一个纹理或者纹理单元,GLSL不关心纹理单元的底层实现,因此它提供了
一个简单而不透明的句柄来封装需要查找的对象。这些句柄被称为"取样器(SAMPLERS)",可
用的取样器类型有:
sampler1D访问一维纹理
sampler2D访问二维纹理
sampler3D访问三维纹理
samplerCube访问立方贴图纹理
sampler2DRect访问二维矩形纹理
sampler1DShadow访问带对比的一维深度纹理
sampler2DShadow访问带对比的二维深度纹理
sampler2DRectShadow访问带对比的二维矩形深度纹理
sampler1DArray访问一维纹理数组
sampler2DArray访问二维纹理数组
sampler1DArrayShadow访问一维深度纹理数组
sampler2DArrayShadow访问二维深度纹理数组
samplerBuffer访问纹理缓存
isampler1D访问整型一维纹理
isampler2D访问整型二维纹理
isampler3D访问整型三维纹理
isamplerCube访问整型立方体贴图纹理
isampler2DRect访问整型二维矩形纹理
isampler1DArray访问整型一维纹理数组
isampler2DArray访问整型二维纹理数组
isamplerBuffer访问整型纹理缓存
usampler1D访问无符号整型一维纹理
usampler2D访问无符号整型二维纹理
usampler3D访问无符号整型三维纹理
usamplerCube访问无符号整型立方贴图纹理
usampler2DRect访问无符号整型二维矩形纹理
usampler1DArray访问无符号整型一维纹理数组
usampler2DArray访问无符号整型二维纹理数组
usamplerBuffer访问无符号整型纹理缓存

着色器程序本身不能初始化取样器,只能通过一个uniform限定的取样器从OpenGL程序中接
收取样器,或者将取样器传递给用户内置函数。作为一个函数参数,取样器不能被修改,因此
着色器程序不能更改一个取样器的值。
Example:
uniform sampler2D Grass;
然后可以将这个变量Grass差U年底到对应的纹理查找函数中,以便访问一个纹理:
vec2 coord;
vec4 color = texture2D(Grass, coord);
coord是一个vec2,存储要用来作为草地纹理的索引的二维位置,color是执行纹理查找
返回的结果。编译器和OpenGLAPI会一起验证Grass确实封装了一个二维纹理,并且会
验证Grass只被传递到二维纹理查找中。
着色器可能不会处理取样器值。例如:表达式Grass+1 是不被允许的。如果一个着色器
需要在程序里结合多个纹理,那么可以使用这样一个取样器数组:
const int NumTextures = 4;
uniform sampler2D textures[NumTextures];
可以在一个循环中处理它们:
for(int i=0;i
color=texture2D(textures[i],coord);
然后,Grass+1 就相当于纹理[GrassIndex +1 ],这是指定取样器将使用哪一个纹理的
有效方式。

5、结构
GLSL提供了类似于C 的用户定义结构。例如:
struct light
{
vec3 position;
vec3 color;
}
就像在C++中一样,结构的名称是这个新的用户定义类型的名称。这里不需要typedef。事
实上GLSL仍然保留了typedef关键字,只是在这里暂时不需要。根据上面的例子,可以像下
面这样声明类型为light的变量:
light ceilingLight;
结构的其他大多数方面都类似于C 。用户可以嵌入和嵌套它们。嵌入的结构类型名称的作用
域与在其中声明了它们 结构的作用域相同。不过嵌入的结构不能是匿名的。结构成员可以是
数组。结构的每一个级别都具有它自己的名称空间,以用于其成员的名称。如:
struct cube

vec3 position;
vec3 color;
}
这里的cube与light都有名为position和color的成员,但是由于二者具有不同的名称空间,
所以不会出现重名的情况。目前结构是GLSL中唯一的用户定义的类型。

6、数组
GLSL可以创建任何类型的数组。声明:
vec4 points[10];
创建的是一个包含 10 个vec4类型的数组。在GLSL中不存在指针。声明数组的唯一方式就是
使用中括号。在声明数组是可以不必指定数组的大小长度。下面这样的声明是可行 :
vec4 points[];
只要符合下面的两种情况之一:
(1) 在引用数组之前,要使用大小再次声明它,其类型与第一次声明时保持一致。例如:
vec4 points[];// 第一次声明 未指定大小长度。
vec4 points[10];//points现在指明了长度和大小,一个包含10个vec4类型的数组。
但是不能在上述两次生命后再次声明,如:
vec4 points[];//初次声明,未指定大小长度
vec4 points[10];//使用前声明,指定了大小长度
vec4 points[20];//非法
vec4 points[];//非法
(2) 静态引用数组的所有索引都是编译时常量。在这种情况下,编译器会使数组足够大,以
便存储它看到的是被使用的最大索引。例如:
vec4 points[];//一个未知大小的数组
points[2] = vec4(1.0);//points现在是一个长度为3 的数组
points[7] = vec4(2.0);//points现在是一个长度为8的数组
在这种情况下,在运行是数组只有一个大小,这是有编译器看到的最大索引决定 。
这个特性对于处理纹理坐标的内置数组非常有用。在内部,这个数组的声明如下:
varying vec4 gl_TexCoord[];
如果一个程序只使用编译时常量索引 0 和 1 ,那么数组的大小将隐式的成为
gl_TexCoord[2]。如果一个着色器使用一个非常量变量作为数组的索引,那么这个着色器
就必须使用需要的大小明确声明该数组。当然,保持其大小尽可能小时很重要的,对易变
变量而言尤其如此,因为它们只能消耗有限的硬件资源。
共享同一个数组的多个着色器可以分别使用不同的大小来声明它。连接器会将数组的大
小,指定为所有链接到一起的着色器中出现的最大索引值。

7、void
在GLSL中,void除了用来表示函数没有返回值外,没有其他用途。


限定符
变量和函数形参都可以使用限定符前缀修饰。使用限定符可以修饰函数的形参(const, in, out, 
inout)。
attribute    :用于经常更改的信息,从OpenGL应用程序到顶点着色器
uniform     :用于不经常更改的信息,用于顶点着色器和片段着色器
varying 用于从顶点着色器传递到片段着色器差值得到的信息。
const :用来声明只读的编译时常量变量(和C差不多)

1、Attribute
属性限定变量(或属性变量)。用来使OpenGL应用程序将经常修改的数据传递到顶点着色器
中。属性变量局限于浮点数标量,浮点数矢量,和矩阵。属性变量不支持 整数、布尔值、结
构或者属性数组。属性变量不能在片段着色器中声明。

2、Uniform
一致限定变量(或一致变量)。一致变量与属性变量一样,只能够在着色器程序的外部设置,
与属性变量不同的是,属性变量是用于经常频繁更改的数据,而一致变量是用于较少更改的数
据。一致限定变量支持所有的数据类型和所有的数据类型的数组。
在同一个OpenGL程序中,所有的顶点着色器和片段着色器会共享一个由一致变量使用的全
局名称空间。因此,顶点着色器和片段着色器中,具有相同名称的一致变量将会是同一个一致
变量。
一致变量不能被着色器写入。因为一致变量在着色器中是共享的,修改一致变量的话,其他
引用则会可能很出错。

3、Varying
易变限定变量(或易变变量)。易变变量是顶点着色器与片段着色器交流的唯一方式。易变变
量是顶点着色器与片段着色器之间的动态接口。
易变变量通常是在定点着色器中写入,片段着色器中读取。片段着色器写入易变变量是非法
的。

4、const
常量。限定为const的变量是编译时常量。这些变量在声明它们的着色器外部是不可见的。
GLSL支持非标量常量。如:
const vec2 v=vec2(1.0,2.0);

5、缺少限定符
如果在声明变量时候,没有指定限定符,那么着色器可以写入和读取这个变量。在全局范围
上声明的未限定变量,可以在同一个程序中链接的同类型的着色器之间共享。顶点着色器和片
段着色器分别拥有自己的用来针对未限定变量的全局命名空间。由于顶点着色器和片段着色器
二者命名空间的差异,所以通过未限定变量来交流信息数据是不行的。

你可能感兴趣的:(openGL)