iOS开发OpenGL ES学习 - 深入着色器

在上一篇已经讲过着色器了,但只是简单的介绍了着色器语言的数据类型,这里就继续介绍着色器语言,让你更全面的了解GLSL语言。

在前面我们已经知道OpenGL的渲染过程,其中的顶点着色器和片段着色器都是可编程的。顶点着色器是负责应用程序传入的顶点数据处理,而片段着色器主要是做最后显示的像素处理,这也说明为什么片段着色器无法直接接受顶点数据的原因。

关于着色器的基本编写与应用在前面的文章中已经说过。Xcode中可以在新建文件 -> Other -> Empty保存文件名后缀为.glsl即可。
然后就是着色器源码的运行时编译,这个在前面也有封装。

GLSL语法:
先可以看下上一篇的vetexShader源码

attribute vec4 Position;
void main(void) {
     gl_Position = Position;
}

比较简单,在接受到顶点数据之后不做任何处理直接赋值给gl_Position。

而片段着色器:

uniform vec4 color;
void main(void) {
    gl_FragColor = color;
}

我们定义了一个uniform属性,相当于全局属性,可以从应用程序中直接传值。

GLSL变量声明:
我们先看一下做过改进的着色器

attribute vec4 position;
attribute vec4 color;
uniform float variable;
varying vec4 fColor;
void main(void) {
    fColor = color;
    float xPos = position.x * sin(variable);
    float yPos = position.y * sin(variable);
    gl_Position = vec4(xPos, yPos, position.z, 1.0);
}

先看属性声明:
1.顶点位置属性:attribute是变量类型,vec4是数据类型,position是变量名
3.uniform:相当于定义的全局变量
4.varying:传递给片段着色器的变量,因为片段着色器无法直接接受顶点数据。

主函数体:
1.将传入的颜色数据color不作任何修改赋值给fColor
2.将位置变量的x值sin(change),其中change是应用程序传入
3.同样将位置变量的y值
sin(change)
4.赋值给gl_Position

下面再看片段着色器:

varying lowp vec4 fColor;
void main(void) {
    gl_FragColor = fColor;
}

比较简单,定义一个varying类型的4分享向量fColor以接受顶点着色器传入的颜色数据fColor未做处理直接赋值给gl_FragColor

看一下处理的最终效果:

对于顶点着色器中的处理不难理解,把顶点坐标的x和y乘以一个常量的正弦值,因为sin()值域在-1和1之间,所以三角形的顶点坐标会在正负之间转换,如果为0的话,那么就是在正中心,所以才有出现三角形颠倒转换和大小的收缩。

既然可以改变顶点坐标,那么我们也可以试试改变图形颜色,这里直接操作片段着色器即可:

precision highp float;
varying lowp vec4 fColor;
uniform float variable;
void main(void) {

// sin()的值域在[-1,1],而颜色分量值在0和1之间,所以将!sin()+1) / 2
    float scale = (sin(variable) + 1.0) / 2.0;
    gl_FragColor = fColor * scale;
}

第一行是指明变量的精度,在fragment shader的变量只能是uniform和varying,这里的varying是从Vertex Shader传过来的值。与Vertex Shader不同的是,这里的变量都要声明精度,比如 highp float processedElapsedTime = elapsedTime;中的highp代表高精度。精度包括lowp highp mediump,低精度,高精度,中等精度。如果你不想为每一个变量都指定精度可以在第一行写上precision highp float; ,当然这只是为float指定默认精度highp。要为其他类型指定精度的话继续加就好了。

在应用程序中,我们需要新增代码为change属性复制:

GLuint variableLoca = glGetUniformLocation(program, "variable");
glUniform1f(variableLoca, (GLfloat)self.changeValue);

先获取uniform highp float variable的位置,因为variable是float类型,所以使用glUniform1f进行赋值。

最后效果如下:

我们还可以设置每个顶点坐标进行旋转,从而达到整个三角形都在旋转的效果:

需要源码可以移步GitHub

参考《OpnGL ES编程指南》