赞
踩
如何编写着色器小程序?
需要用到一门新的语言,GLSL,它是类似C风格的语言。
GLSL全称为OpenGL Shading Language,是为了实现着色器的功能
而向开发人员提供的一种开发语言,对其只要能理解到这个层次就可以
了。
GLSL语法与内建函数
修饰符
基本数据类型
int、float、bool,这些与C语言都是一致的,需要强调的一点就是,这里面的float是有一个修饰符的,即可以指定精度。三种修饰符的范围(范围一般视显卡而定)和应用情况具体如下。
向量类型
向量类型是Shader中非常重要的一个数据类型,因为在做数据传递的时候需要经常传递多个参数,相较于写多个基本数据类型,使用向量类型是非常好的选择。列举一个最经典的例子,要将物体坐标和纹理坐标传递到Vertex Shader中,用的就是向量类型,每一个顶点都是一个四维向量,在Vertex Shader中利用这两个四维向量即可完成自己的纹理坐标映射操作。
声明方式如下(GLSL代码)
attribute vec4 position;
矩阵类型
矩阵类型在Shader的语法中也是一个非常重要的类型,有一些效果器需要开发者传入矩阵类型的数据,比如后面会接触到的怀旧效果器,就需要传入一个矩阵来改变原始的像素数据。声明方
式如下(GLSL代码):
uniform lowp mat4 colorMatrix;
上面的代码表示了一个4×4的浮点矩阵,如果是mat2就是2×2的浮点矩阵,如果是mat3就是3×3的浮点矩阵。若要传递一个矩阵到实际的Shader中,则可以直接调用如下函数(客户端代码):
glUniformMatrix4fv(mColorMatrixLocation, 1, false, mColorMatrix,0);
纹理类型
一般仅在Fragment Shader中使用这个类型,二维纹理的声明方式如下(GLSL代码):
uniform sampler2D texSampler;
当客户端接收到上面这个句柄时,就可以为它绑定一个纹理,代码如下(客户端代码):
- //激活图层
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- // 图像数据
- // 正常:GLES20.GL_TEXTURE_2D
- // surfaceTexure的纹理需要
- GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,texture);
- //传递参数 0:需要和纹理层GL_TEXTURE0对应
- GLES20.glUniform1i(vTexture,0);
注意上述代码中第一行激活的是哪一个纹理句柄,第三行代码中的第二个参数需要传递对应的Index,就像代码中激活的纹理句柄是GL_TEXTURE0,对应的Index就是0,如果激活的纹理句柄是GL_TEXTURE1,那么对应的Index就是1,在不同的平台上句柄的个数也不一样,但是一般都会在32个以上。
特殊的传递类型
在GLSL中有一个特殊的修饰符就是varying,这个修饰符修饰的变量均用于在Vertex Shader和
Fragment Shader之间传递参数。首先在顶点着色器中声明这个类型的变量代表纹理的坐标点,并且对这个变量进行赋值,代码如下:
- //传给片元着色器 像素点
- varying vec2 aCoord;
- void main(){
- //内置变量 gl_Position ,我们把顶点数据赋值给这个变量 opengl就知道它要画什么形状了
- gl_Position = vPosition;
- // 经过测试 和设备有关, 计算顶点坐标
- aCoord = (vMatix * vCoord).xy;
- }
紧接着在Fragment Shader中也声明同名的变量,然后使用texture2D方法取出二维纹理中该纹理坐标点上的纹理像素值,代码如下(GLSL代码):
- //采样点的坐标
- varying vec2 aCoord;
- //采样器
- uniform samplerExternalOES vTexture;
- void main(){
- //变量 接收像素值
- // texture2D:采样器 采集 aCoord的像素
- //赋值给 gl_FragColor 就可以了
- gl_FragColor = texture2D(vTexture,aCoord);
- }
取出了该坐标点上的像素值之后,就可以进行像素变化操作了,比如说提高对比度,最终将改变的像素值赋值给gl_FragColor。
GLSL的内置函数与内置变量
首先来看内置变量,最常见的是两个Shader的输出变量。先来看Vertex Shader的内置变(GLSL代码):
原型
vec4 gl_position;
使用
- // 把顶点坐标给这个变量, 确定要画画的形状
- attribute vec4 vPosition;
- void main(){
- //内置变量 gl_Position ,我们把顶点数据赋值给这个变量 opengl就知道它要画什么形状了
- gl_Position = vPosition;
- }
上述代码用来设置顶点转换到屏幕坐标的位置,Vertex Shader一定要去更新这个数值。另外还有一个内置变量,代码如下(GLSL代码):
原型
float gl_pointSize;
其次是Fragment Shader的内置变量,代码如下(GLSL代码):
原型
vec4 gl_FragColor;
上述代码用于指定当前纹理坐标所代表的像素点的最终颜色值。
然后是内置函数,具体的函数可以去官方文档中查询,这里仅介绍几个常用的函数。
对于一个语言的语法来讲,剩下的就是控制流部分了,而GLSL的控制流与C语言非常类似,既可以使用for、while以及do-while实现循环,也可以使用if和if-else进行条件分支的操作。
GLSL的常用语法部分已经讲解得差不多了,毕竟程序(Shader)都是运行在GPU上的,那么在CPU上运行的程序(应用程序)应该如何将这一组Shader交给OpenGL ES的渲染管线呢?下面就来介绍如何在应用程序中使用Shader。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。