shader 内置变量

来源:互联网 发布:客户数据库系统excl 编辑:程序博客网 时间:2024/04/29 03:08

GLSL学习

一个OpenGL程序可以用多种方式和shader通信。注意这种通信是单向的,因为shader的输出只能是渲染到某些目标,比如颜色和深度缓存。

OpenGL的部分状态可以被shader访问,因此程序改变OpenGL某些状态就可以与shader进行通信了。例如一个程序想把光的颜色传给shader,可以直接调用OpenGL接口,就像使用固定功能流水线时做的那样。

不过,使用OpenGL状态并不是设置shader中使用数据的直观方式。比如一个shader需要一个表示时间变化的变量来计算动画,在OpenGL状态中就没有现成的变量可用。当然,你可以使用没有用到的“镜面光截止角度(cutoffangle)”这样一个变量表示时间,但显然让人难以接受。
幸运的是,GLSL允许用户自定义变量,实现OpenGL应用程序与shader通信。有了这个功能,你就可以命名一个叫做timeElapsed的变量表示经过的时间。

上文的讨论涉及到了GLSL提供的两种类型修饰符(更多的类型将在后面提到):

  • 一致变量(Uniform)
  • 属性(Attribute)

在shader中定义的变量如果用这两种类型修饰符,表示对shader来说,它们是只读的。下面将详细讲述怎样使用这些类型的变量。
还有一种将变量送给shader的方法:使用纹理。一个纹理不止可以表示一张图片,它还可以表示一个数组。事实上,你完全可以决定如何在shader中解释纹理数据,即使它真是一幅图片。

##变量修饰符

修饰符给出了变量的特殊含义,GLSL中有如下修饰符:

  • const – 声明一个编译期常量。
  • attribute– 随不同顶点变化的全局变量,由OpenGL应用程序传给顶点shader。这个修饰符只能用在顶点shader中,在shader中它是一个只读变量。
  • uniform– 随不同图元变化的全局变量(即不能在glBegin/glEnd中设置),由OpenGL应用程序传给shader。这个修饰符能用在顶点和片断shader中,在shader中它是一个只读变量。
  • varying –用于顶点shader和片断shader间传递的插值数据,在顶点shader中可写,在片断shader中只读。

###一致变量(Uniform Variables)

不同于顶点属性在每个顶点有其自己的值,一个一致变量在一个图元的绘制过程中是不会改变的,所以其值不能在glBegin/glEnd中设置。一致变量适合描述在一个图元中、一帧中甚至一个场景中都不变的值。一致变量在顶点shader和片断shader中都是只读的。

首先你需要获得变量在内存中的位置,这个信息只有在连接程序之后才可获得。注意,对某些驱动程序,在获得存储位置前还必须使用程序(调用glUseProgram)。

获取一个一致变量的存储位置只需要给出其在shader中定义的变量名即可:

GLint glGetUniformLocation(GLuint program, const char *name);·program – the hanuler to the program·name – the name of the variablevoid glUniform1f(GLint location, GLfloat v0);void glUniform2f(GLint location, GLfloat v0, GLfloat v1);void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);或者GLint glUniform{1,2,3,4}fv(GLint location, GLsizei count, GLfloat *v);参数:·location – the previously queried location·v0,v1,v2,v3 – float values·count – the number of elements in the array·v – an array of floats

对integer类型也有一组类似的函数,不过要用i替换函数中的f。对bool类型没有专门的函数,但可以使用整数的0和1来表示真假。一旦你使用了一致变量数组,那么就必须使用向量版本的函数。

对sampler变量,使用函数glUniform1i和glUniform1iv。

矩阵也是一种GLSL的数据类型,所以也有一组针对矩阵的函数:glUniformMatrix{1,2,3,4}fv

还有一点要注意的是:使用这些函数之后,变量的值将保持到程序再次连接之时。一旦进行重新连接,所有变量的值将被重置为0。

###属性变量(Attribute Variables)

在前一节提到,一致变量只能针对一个图元全体,就是说不能在glBegin和glEnd之间改变。

如果要针对每个顶点设置变量,那就需要属性变量了。事实上属性变量可以在任何时刻更新。在顶点shader中属性变量是只读的。因为它包含的是顶点数据,所以在片断shader中不能直接应用。

与一致变量相似,首先你需要获得变量在内存中的位置,这个信息只有在连接程序之后才可获得。注意,对某些驱动程序,在获得存储位置前还必须使用程序。

易变变量(Varying Variables)

前面说过,shader包括两种类型:顶点shader和片断shader。为了计算片断的值,往往需要访问顶点的插值数据。例如,当使用逐片断光照时,我们需要知道当前片断的法线,但是在OpenGL中只为每个顶点指定了法线。顶点shader可以访问这些法线,而片断shader不能,因为法线是OpenGL程序作为属性变量指定的。

顶点变换后的数据移动到流水线的下一个阶段,在这个阶段通过使用连接信息,生成了所有图元并完成片断化。对每个片断,有一组变量会被自动进行插值并提供给片断shader,这些都是固定功能。片断的颜色就是这么处理的,到达片断shader的颜色就是组成图元的顶点颜色插值的结果。

像片断shader接收到的这种插值产生的变量,就是“易变变量”类型。GLSL包含一些预先定义的易变变量,例如前面提到的颜色。用户也可以自己定义易变变量,它们必须同时在顶点shader和片断shader中声明:

varying float intensity;

一个易变变量必须先在顶点shader中声明,然后计算每个顶点的变量值。在片断shader中,接收这个变量通过插值得到的结果,注意此时这个变量是只读的。

GLSL也有跳转语句:

·continue – available in loops, causes a jump to thenext iteration of the loop

·break – available in loops, causes an exit of theloop

·discard

最后的discard关键字只能在片断shader中使用,它将在不写入帧缓存或者深度缓存的情况下,终止当前片断的shader程序。

函数

与C语言类似,shader也是由函数组成的结构化程序。至少每类shader都必须包含一个如下方式声明的主函数:

void main()  

此外用户还可以自定义函数。这些函数像C函数一样,一般都会有返回值,返回值的类型没有限制,但不能是数组。

函数参数可以有如下修饰符:

·in – for input parameters

·out – for outputs of the function. The returnstatement is also an option for sending the result of a function.

·inout – for parameters that are both input andoutput of a function

如果没有指定修饰符,默认情况下为in类型。

最后还有两点要注意:

·允许函数重载,只要参数不同。

·在标准中没有定义递归行为。

0 0
原创粉丝点击