OpenGL ES着色器语言之变量和数据类型和着色器流程

来源:互联网 发布:sql update 编辑:程序博客网 时间:2024/05/16 01:53

感谢原创:

转至:http://www.cnblogs.com/yiyezhai/archive/2012/09/21/2697461.html

          http://blog.csdn.net/kesalin/article/details/8223649

          http://blog.csdn.net/wangyuchun_799/article/details/7744620

          http://blog.csdn.net/jackers679/article/details/6848085

所有变量和函数在使用前必须声明。变量和函数名是标识符。

       没有默认类型,所有变量和函数声明必须包含一个声明类型以及可选的修饰符。变量在声明的时候首先要标明类型,后边可以跟多个变量,之间用逗号隔开。很多情况下,变量在声明的时候可以使用等号“=”进行初始化。

       用户定义类型可以使用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;

        向量的初始化工作可以放在构造函数中完成。

eg:

       vec = vec2(1.0,2.0);

        vec2 b = vec2(3.0,4.0);

        vec = vec4(a,b) // c = vec4(1.0,2.0,3.0,4.0);

        vec = vec2(1.0,2.0);

        float h = 3.0;

        vec3 j = vec3(g,h);

        vec = vec2(1.0,2.0);

        vec2 b = vec2(3.0,4.0);


4.1.6  Matrices

        矩阵是另一个在计算机图形中非常有用的数据类型,OpenGL ES着色语言支持2*2, 3*3, 4*4浮点数矩阵。

           mat2 mat2D;

           mat3 optMatrix;

           mat4 view, projection;

        矩阵的初始化工作可以放在构造函数中完成。

eg.

        mat2 n = mat2(a,b); // matrices are assigned in column major order

        mat2 k = mat2(1.0,0.0,1.0,0.0); // all elements are specified

The declaration and initialization of structures is demonstrated below:

        struct dirlight {              // type definition

               vec3 direction;

               vec3 color;

        };

        dirlight d1;

        dirlight d2 = dirlight(vec3(1.0,1.0,0.0),vec3(0.8,0.8,0.4));

        vec = vec4(1.0,2.0,3.0,4.0);


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隐藏了到底这些空间是如何被矩阵使用的。属性变量需要被声明为全局变量。

attribute变量是只能在vertex shader中使用的变量。(它不能在fragment shader中声明attribute变量,也不能被fragment shader中使用)

一般用attribute变量来表示一些顶点的数据,如:顶点坐标,法线,纹理坐标,顶点颜色等。

application中,一般用函数glBindAttribLocation()来绑定每个attribute变量的位置,然后用函数glVertexAttribPointer()为每个attribute变量赋值。

4.3.4  Uniform

        uniform修饰符用来修饰那些在整个图元被处理的过程中保持不变的全局变量。所有的uniform变量都是只读的,可以通过应用程序调用API命令初始化,或者通过OpenGL ES间接初始化。

                 uniform vec4 lightPosition;

       uniform修饰符可以和任意基本数据类型一起使用,或者包含基本数据类型元素的数组和结构体。每种类型的着色器的uniform变量的存储数量是有限制的,如果超过这个限制,将会引起编译时或链接时错误。声明了但是没有被静态使用的uniform变量不会受到这个限制。静态使用(static use)是指着色器包含变量在预处理以后的一个引用。用户定义的uniform变量和着色器中被静态使用的内建uniform变量将共同决定有没有超出可用uniform存储范围。

       当顶点着色器和片元着色器被链接到一起,它们将共享同一个名称空间。这就意味着,所有被连接到同一个可执行程序的着色器中的同名变量必须也同时具有相同的类型和精度。

uniform变量是外部application程序传递给(vertexfragmentshader的变量。因此它是application通过函数glUniform**()函数赋值的。在(vertexfragmentshader程序内部,uniform变量就像是C语言里面的常量(const),它不能被shader程序修改。(shader只能用,不能改)

如果uniform变量在vertexfragment两者之间声明方式完全一样,则它可以在vertexfragment共享使用。(相当于一个被vertexfragment shader共享的全局变量)

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变量需要声明为全局变量。

varying变量是vertexfragment shader之间做数据传递用的。一般vertex shader修改varying变量的值,然后fragment shader使用该varying变量的值。因此varying变量在vertexfragment shader二者之间的声明必须是一致的。application不能使用此变量。

4.4参数修饰符

        函数参数修饰符有如下几种:

(1)<none: default>,默认情况下,是in

(2)in,作为函数的传入参数

(3)out,作为函数的传出参数

(4)inout,即作为传入参数,又作为传出参数

着色器流程:

着色器,可以理解为运行在显卡中的指令和数据。 
完整的着色器包括顶点着色器和片元着色器。顶点着色器最基本的任务是接收三维空间中点的坐标,将其处理为二维空间中的坐标并输出;片元着色器最基本的任务是对需要处理的屏幕上的每个像素输出一个颜色值;将顶点着色器输出的二维空间中的点坐标,转化为需要处理的像素并传递给片元着色器的过程,称为图元光栅化。

        1

在WebGL中,着色器是用一种类似于C的语言x-shader编写的。

1,顶点着色器

下面来仔细看看顶点着色器:

顶点着色器接收的输入:

Attributes:由 vertext array 提供的顶点数据,如空间位置,法向量,纹理坐标以及顶点颜色,它是针对每一个顶点的数据。属性只在顶点着色器中才有,片元着色器中没有属性。属性可以理解为针对每一个顶点的输入数据。OpenGL ES 2.0 规定了所有实现应该支持的最大属性个数不能少于 8 个。

Uniforms:uniforms保存由应用程序传递给着色器的只读常量数据。在顶点着色器中,这些数据通常是变换矩阵,光照参数,颜色等。由 uniform 修饰符修饰的变量属于全局变量,该全局性对顶点着色器与片元着色器均可见,也就是说,这两个着色器如果被连接到同一个应用程序中,它们共享同一份 uniform 全局变量集。因此如果在这两个着色器中都声明了同名的 uniform 变量,要保证这对同名变量完全相同:同名+同类型,因为它们实际是同一个变量。此外,uniform 变量存储在常量存储区,因此限制了 uniform 变量的个数,OpenGL ES 2.0 也规定了所有实现应该支持的最大顶点着色器 uniform 变量个数不能少于 128 个,最大的片元着色器 uniform 变量个数不能少于 16 个。

Samplers:一种特殊的 uniform,用于呈现纹理。sampler 可用于顶点着色器和片元着色器。

Shader program:由 main 申明的一段程序源码,描述在顶点上执行的操作:如坐标变换,计算光照公式来产生 per-vertex 颜色或计算纹理坐标。

顶点着色器的输出:

Varying:varying 变量用于存储顶点着色器的输出数据,当然也存储片元着色器的输入数据,varying 变量最终会在光栅化处理阶段被线性插值。顶点着色器如果声明了 varying 变量,它必须被传递到片元着色器中才能进一步传递到下一阶段,因此顶点着色器中声明的 varying 变量都应在片元着色器中重新声明同名同类型的 varying 变量。OpenGL ES 2.0 也规定了所有实现应该支持的最大 varying 变量个数不能少于 8 个。

在顶点着色器阶段至少应输出位置信息-即内建变量:gl_Position,其它两个可选的变量为:gl_FrontFacing 和 gl_PointSize。

2,片元着色器

接下来仔细看看片元着色器:


片元管理器接受如下输入: 

Varyings:这个在前面已经讲过了,顶点着色器阶段输出的 varying 变量在光栅化阶段被线性插值计算之后输出到片元着色器中作为它的输入,即上图中的 gl_FragCoord,gl_FrontFacing 和 gl_PointCoord。OpenGL ES 2.0 也规定了所有实现应该支持的最大 varying 变量个数不能少于 8 个。

Uniforms:前面也已经讲过,这里是用于片元着色器的常量,如雾化参数,纹理参数等;OpenGL ES 2.0 也规定了所有实现应该支持的最大的片元着色器 uniform 变量个数不能少于 16 个。

Samples:一种特殊的 uniform,用于呈现纹理。

Shader program:由 main 申明的一段程序源码,描述在片元上执行的操作。

在顶点着色器阶段只有唯一的 varying 输出变量-即内建变量:gl_FragColor。


0 0
原创粉丝点击