cocos2D-X源码分析之从cocos2D-X学习OpenGL(7)----GLSL

时间:2022-06-08 12:07:45

       上一篇博客介绍了cocos2d-x中的着色器类相关的结构,以及着色器的一些原理,这一篇将介绍着色器语言。

       GLSL(openGL shading langueage)openGL着色器语言可视为一种类C语言并包含某些扩展操作以及限制条件,从纯语言观点来看,GLSL语言包含了早期程序设计语言中的某些特征,例如,某些特殊变量可访问通过openGL应用程序设置的数据并置于板载寄存器中;针对于图形需求,基于向量和矩阵的特定操作;特定变量类型,以反映基于变量实现、不同类型的操作;共享命名空间,以提供应用程序、顶点着色器以及片元着色器之间的通讯能力。

       废话少说,我们从上一篇已经打开的着色器代码中

#ifdef GL_ES
attribute mediump vec4 a_position;
attribute mediump vec2 a_texcoord;
attribute mediump vec4 a_color;

varying mediump vec4 v_color;
varying mediump vec2 v_texcoord;

#else

attribute vec4 a_position;
attribute vec2 a_texcoord;
attribute vec4 a_color;

varying vec4 v_color;
varying vec2 v_texcoord;

#endif

void main()
{
v_color = vec4(a_color.rgb * a_color.a, a_color.a);
v_texcoord = a_texcoord;

gl_Position = CC_MVPMatrix * a_position;
}
       GLSL很类似于C代码,它是一种强类型语言,所有变量都必须事先声明,并且要给出变量的类型。变量名称的命名规范与C语言相同,虽然所有的变量都需要声明,但是我们可以在使用它们之前的任何时候声明这些变量。这个顶点着色器的例子里,我们在文件的开头声明了所需要的变量,首先用预编译命令区分是否在openGL es下,我们可以发现,两段声明的不同之处,就是加入了mediump这个精度限定符,它使程序员可以指定着色器变量的计算精度,在较低的精度下,有些openGL es实现在运行着色器时可能更快,或者电源效率更高,当然,这种效率提升是以牺牲运算精度为代价的,有可能会造成显示的错误,精度限制符分为高中低三档,分别为highp,mediump和lowp,我们可以在着色器开头指定默认精度限制符,代码如下:
precision mediump int;
       这样一来,后面的所有int型的变量不用加精度限制符,就是中等的精度;如果不设置默认精度的情况下,顶点着色器中的int和float都是highp,也就是说都是高精度的;而在片段着色器中,就没有默认精度了。

       attribute是一个类型限定符,它扩展了原有C语言功能集,它包括const,attrbute,uniform,varying等

       const:该变量为编译器常量,且无法在着色器外部使用,不可以被赋值。

       attribute:仅用于顶点着色器中,并以逐点方式通过应用程序进行设定,源自应用程序并发送到图形卡中,比如例子中的位置a_position,贴图a_texcoord和颜色a_color都是在上一篇中的应用代码中传入着色器中,并进行进一步处理,传到图形卡中。

       uniform:定义于着色器外部,不需要在着色器中传递,在使用它的着色器中声明即可,它是只读类型,uniform变量通常被保存在硬件中,这个区域被称为“常量存储”,是硬件中存储常量的特殊空间,大小固定

       varying:是在着色器之间传递的变量,它可以由某一个着色器修改后传递给另外一个着色器,可以理解为着色器间的传递值得变量,本例中的v_color和v_texcoord就是会传递给下一个片段着色器。

       在着色器之间传递的变量也用in或out来修饰,in变量是从着色器上一个管线中接收,并可视为当前着色器的只读变量。out变量从其定义的着色器获取值,并把它传递到下一个着色器中,为着色器中的只写变量。另外这个修饰符也可以修饰函数的参数。

       着色器的控制流语句,函数和数组与c语言的使用别无二致,这里就不再赘述了。

       片段着色器的代码如下:

#ifdef GL_ESvarying mediump vec4 v_color;varying mediump vec2 v_texcoord;#elsevarying vec4 v_color;varying vec2 v_texcoord;\n#endif\nvoid main(){    gl_FragColor = v_color*step(0.0, 1.0 - length(v_texcoord));}
       可以看到接受了顶点着色器传来的数据并做了进一步处理,step和length都是内建函数,openGL有很多内建函数,处理通常在着色器中进行各种计算任务,具体的内建函数会在用到时详细说明。

       下一篇将介绍贴图

       能力不足,水平有限,如有错误,欢迎指出。