OpenGL ES着色器语言之变量和数据类型(一)(官方文档第四章)
所有变量和函数在使用前必须声明。变量和函数名是标识符。
没有默认类型,所有变量和函数声明必须包含一个声明类型以及可选的修饰符。变量在声明的时候首先要标明类型,后边可以跟多个变量,之间用逗号隔开。很多情况下,变量在声明的时候可以使用等号“=”进行初始化。
用户定义类型可以使用struct,在结构体中所有变量类型都必须是OpenGL ES着色器语言定义的关键字。OpenGL ES着色语言是类型安全的,因此不支持隐式类型转换。
4.1 基本数据类型
4.1.1 void
函数没有返回值必须声明为void,没有默认的函数返回值。关键字void不能用于其他声明,除了空形参列表外。
4.1.2 Booleans
布尔值,只有两个取值true或false。
bool success, done = false;
4.1.3 Integers
整型主要作为编程的援助角色。在硬件级别上,真正地整数帮助有效的实现循环和数组索引,纹理单元索引。然而,着色语言没必要将整型数映射到硬件级别的整数。我们并不赞成底层硬件充分支持范围广泛的整数操作。OpenGL ES着色语言会把整数转化成浮点数进行操作。整型数可以使用十进制(非0开头数字),八进制(0开头数组)和十六进制表示(0x开头数字)。
int i, j = 42;
4.1.4 Floats
浮点型用于广泛的标量计算。可以如下定义一个浮点数:
float a, b = 1.5;
4.1.5 Vectors
OpenGL ES着色语言包含像2-,3-, 4-浮点数、整数、booleans型向量的泛型表示法。浮点型向量可以保存各种有用的图形数据,如颜色,位置,纹理坐标。
vec2 texCoord1, texCoord2;
vec3 position;
vec4 rgba;
ivec2 textureLookup;
bvec3 lessThan;
向量的初始化工作可以放在构造函数中完成。
4.1.6 Matrices
矩阵是另一个在计算机图形中非常有用的数据类型,OpenGL ES着色语言支持2*2, 3*3, 4*4浮点数矩阵。
mat2 mat2D;
mat3 optMatrix;
mat4 view, projection;
矩阵的初始化工作可以放在构造函数中完成。
4.1.7 Sampler
采样器类型(如sampler2D)实际上是纹理的不透明句柄。它们用在内建的纹理函数来指明要访问哪一个纹理。它们只能被声明为函数参数或uniforms。除了纹理查找函数参数, 数组索引, 结构体字段选择和圆括号外,取样器不允许出现在表达式中。取样器不能作为左值,也不能作为函数的out或inout参数。这些限制同样适用于包含取样器的的结构体。作为uniforms时,它们通过OpenGL ES API初始化。作为函数参数,仅能传入匹配的采样器类型。这样可以在着色器运行之前进行着色器纹理访问和OpenGL ES纹理状态的一致性检查。
4.1.8 Structures
通过结构体用户可以创建自己的数据类型。
struct light{
float intensity;
vec3 position;
}lightVar;
结构体不支持内部匿名结构体对象,也不支持内部嵌入结构体,但可以声明另一个结构体的变量。
4.1.9 Arrays
同种类型的变量可以放在一个数组中保存和管理。数组长度必须是大于0的常整型数。用负数或大于等于数组程度的索引值索引数组是不合法的。数组作为函数形参必须同时指明数组长度。仅支持一维数组,基本数据类型和结构体类型都可以作为数组元素。
float frequencies[3];
uniform vec4 lightPosition[4];
const int numLights = 2;
light lights[bumLights];
不能在着色器中声明数组的同时进行初始化。
4.2 Scopes
声明的范围决定了变量的可见性。GLSL ES使用了静态嵌套范围,允许在着色器内重定义一个变量。
4.2.1术语的定义
术语scope说明程序的一个特定的区域,在这个区域定义的变量时可见的。
4.2.2范围类型
4.2.3 重声明变量
在一个编译单元,具有相同名字的变量不能重声明在同一个范围。可以在不同的范围内声明同名的变量,但没有办法访问外层范围的同名变量。
4.2.4共享全局变量
共享全局变量是指可以在多个编译单元访问的变量。在GLSL ES中仅uniform变量可以作为全局共享变量。varying变量不能作为全局共享变量因为在片元着色器能读取它们之前必须通过光栅化传递。
共享全局变量必须有相同的名字, 存储和精度修饰符。它们必须有如下相同等价的规则:必须具有相同的精度,基本类型和尺寸。标量必须有一样的类型名称和类型定义,而且字段名称必须为相同类型。
4.3存储修饰符
本地变量只能使用存储修饰符const。
函数参数只能用const。函数返回值类型和结构体字段不要使用const。
从一个运行时着色器到下一个运行时着色器之间进行数据类型通信是不存在的。这阻止了同一个着色器在多个顶点和片元之间同时执行。
没有存储修饰符或仅仅使用const修饰符的全局变量,可能在main()执行前进行初始化。Uniforms, attributes和varyings可能没有初始化器。
4.3.1默认存储修饰符
如果在全局变量前没有修饰符,那么它们就与应用程序和其他处理器上的着色器没有关联。对于全局或本地的无修饰符变量,声明都会在其所属的那个处理器上分配内存。这个变量将提供对分配的内存的读写访问。
4.3.2常量修饰符
命名的编译时常量可以用const声明。任何使用const声明的变量在其所属的着色器中均是只读的。将变量声明为常量可以减少使用硬连线的数字常数。const可以用来修饰任何基本数据类型。通常const变量在声明的同时要进行初始化:
const vec3 zAxis = vec3 (0.0, 0.0, 1.0);
结构体字段不能使用const修饰吗,但是变量可以,并通过构造器进行初始化。包含数组的数组和结构体不能声明为常量,因为它们不能被初始化。
4.3.3 Attribute
attribute修饰符用于声明通过OpenGL ES应用程序传递到顶点着色器中的变量值。在其它任何非顶点着色器的着色器中声明attribute变量是错误的。在顶点着色器被程序使用之前,attribute变量是只读的。attribute变量的值通过OpenGL ES顶点API或者作为顶点数组的一部分被传进顶点着色器。它们传递顶点属性值到顶点着色器,并且在每一个运行的顶点着色器中都会改变。attribute修饰符只能修饰float, vec2, vec3, vec4,mat2,mat3,mat4。attribute变量不能声明为数组或结构体。如:
attribute vec4 position;
attribute vec3 normal;
attribute vec2 texCoord;
大家可能希望图形硬件有极少量的固定位置来传递顶点属性。所以,OpenGL ES为每一个非矩阵变量赋予了升级到4个浮点数值的空间,如vec4。在OpenGL ES中,可以使用的属性变量个数是有限制的,如果超过这个限制,将会引起链接错误。(声明了但没有使用的属性变量不会受到这个限制。)一个浮点数属性也要受到这个限制,所以你应该尽量将四个毫不相关的float变量打包成一个pack,以优化底层硬件的兼容性。一个mat4和使用4个vec4变量是一致的,同理,一个mat3和使用3个vec3变量是一致的,一个mat2和使用2个vec2变量是一致的。着色语言和API隐藏了到底这些空间是如何被矩阵使用的。属性变量需要被声明为全局变量。
4.3.4 Uniform
uniform修饰符用来修饰那些在整个图元被处理的过程中保持不变的全局变量。所有的uniform变量都是只读的,可以通过应用程序调用API命令初始化,或者通过OpenGL ES间接初始化。
uniform vec4 lightPosition;
uniform修饰符可以和任意基本数据类型一起使用,或者包含基本数据类型元素的数组和结构体。每种类型的着色器的uniform变量的存储数量是有限制的,如果超过这个限制,将会引起编译时或链接时错误。声明了但是没有被静态使用的uniform变量不会受到这个限制。静态使用(static use)是指着色器包含变量在预处理以后的一个引用。用户定义的uniform变量和着色器中被静态使用的内建uniform变量将共同决定有没有超出可用uniform存储范围。
当顶点着色器和片元着色器被链接到一起,它们将共享同一个名称空间。这就意味着,所有被连接到同一个可执行程序的着色器中的同名变量必须也同时具有相同的类型和精度。
4.3.4 Varying
varying变量提供了顶点着色器,片元着色器和二者通讯控制模块之间的接口。顶点着色器计算每个顶点的值(如颜色,纹理坐标等)并将它们写到varying变量中。顶点着色器也会从varying变量中读值,获取和它写入相同的值。如果从顶点着色器中读取一个尚未被写入的varying变量,将返回未定义值。
通过定义,每个顶点的varying变量以一种透视校正的方式被插入到正在渲染的图元上。如果是单采样,插值为片元中心。如果是多采样,插值可以是像素中的任何地方,包括片元中心或者其中一个片元采样。
片元着色器会读取varying变量的值,并且被读取的值将会作为插值器,作为图元中片元位置的一个功能信息。varying变量对于片元着色器来说是只读的。
在顶点和片元着色器中都有声明的同名varying变量的类型必须匹配,否则将引起链接错误。
下表总结了顶点和片元着色器匹配的规则:
术语“静态使用”意思是在预处理之后,着色器至少包含一个访问varying变量的语句,即使这个语句没有真正执行过。
varying vec3 normal;
varying修饰符只能用在float, vec2, vec3, vec4, mat2, mat3, mat4和包含这些类型元素的数组上,不能用于修饰结构体。
varying变量需要声明为全局变量。
4.4参数修饰符
函数参数修饰符有如下几种:
(1)<none: default>,默认情况下,是in
(2)in,作为函数的传入参数
(3)out,作为函数的传出参数
(4)inout,即作为传入参数,又作为传出参数
OpenGL ES着色语言之varying,uniform,attribute修饰范围
varying
修饰符只能用在float, vec2, vec3, vec4, mat2, mat3, mat4和包含这些类型元素的数组上,不能用于修饰结构体。
uniform
修饰符可以和任意基本数据类型一起使用,或者包含基本数据类型元素的数组和结构体。
attribute
修饰符只能修饰float, vec2, vec3, vec4,mat2,mat3,mat4。attribute变量不能声明为数组或结构体。