GLSL的语法以及内嵌函数

如何编写着色器小程序?
需要用到一门新的语言,GLSL,它是类似C风格的语言。

GLSL全称为OpenGL Shading Language,是为了实现着色器的功能
而向开发人员提供的一种开发语言,对其只要能理解到这个层次就可以
了。

GLSL语法与内建函数

  • 修饰符
    float? 浮点型
    vec2? 含两个浮点型数据的向量,相当于一个数组
    vec4? 含四个浮点型数据的向量(xyzw,rgba,stpq)
    sampler2D? 2D纹理采样器(代表一层纹理)

修饰符

  • const:用于声明非可写的编译时常量变量。
  • attribute:属性变量。用于经常更改的信息,只能用于顶点着色器中。 一般用该变量来表示一些顶点数据,如:顶点坐标、纹理坐标、颜色等。
  • uniforms:一致变量。用于不经常更改的信息,可用于顶点着色器和片元着色器。在着色器执行期间一致变量的值是不变的。与const常量不同的是,这个值在编译时期是未知的是由着色器外部初始化的。
  • varying:用于修饰从顶点着色器向片元着色器传递的变量。

基本数据类型
int、float、bool,这些与C语言都是一致的,需要强调的一点就是,这里面的float是有一个修饰符的,即可以指定精度。三种修饰符的范围(范围一般视显卡而定)和应用情况具体如下。

  • highp:32bit,一般用于顶点坐标(vertex Coordinate)。
  • medium:16bit,一般用于纹理坐标(texture Coordinate)。
  • lowp:8bit,一般用于颜色表示(color)。

向量类型

向量类型是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;

上述代码用于指定当前纹理坐标所代表的像素点的最终颜色值。

然后是内置函数,具体的函数可以去官方文档中查询,这里仅介绍几个常用的函数。

  • abs(genType x):绝对值函数。
  • floor(genType x):向下取整函数。
  • ceil(genType x):向上取整函数。
  • mod(genType x,genType y):取模函数。
  • min(genType x,genType y):取得最小值函数。
  • max(genType x,genType y):取得最大值函数。
  • clamp(genType x,genType y,genType z):取得中间值函数。
  • step(genType edge,genType x):如果x<edge,则返回0.0,否则返回1.0。
  • smoothstep(genType edge0,genType edge1,genType x):如果x≤edge0,则返回0.0;如果x≥edge1,则返回1.0;如果edge0<x<edge1,则执行0~1之间的平滑差值。
  • mix(genType x,genType y,genType a):返回线性混合的x和y,用公式表示为:x(1-a)+ya,这个函数在mix两个纹理图像的时候非常有用。
    其他的角度函数、指数函数、几何函数在这里就不再赘述了,可以去官方文档进行查询。

对于一个语言的语法来讲,剩下的就是控制流部分了,而GLSL的控制流与C语言非常类似,既可以使用for、while以及do-while实现循环,也可以使用if和if-else进行条件分支的操作。

GLSL的常用语法部分已经讲解得差不多了,毕竟程序(Shader)都是运行在GPU上的,那么在CPU上运行的程序(应用程序)应该如何将这一组Shader交给OpenGL ES的渲染管线呢?下面就来介绍如何在应用程序中使用Shader

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值