GLSL的语法以及内嵌函数

2019-10-11  本文已影响0人  凌烟醉卧

如何编写着色器小程序?
需要用到一门新的语言,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

上一篇 下一篇

猜你喜欢

热点阅读