大家好,下面和大学一起学习如何使用片段着色器fragment shader
来渲染丰富多彩的颜色,在我的github上有一个项目OpenGLES2.0SamplesForAndroid
,我会不断地编写学习样例,文章和代码同步更新,欢迎关注,链接:github.com/kenneycode/…
在上一篇文章中,我们介绍了渲染管线,下面来回顾一下fragment shader
在渲染管线中的位置:
fragment shader
会在光栅化后,对每个像素执行一次,先看一下我们之前的例子中使用的fragment shader
:
precision mediump float;
void main() {
gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
}
复制代码
在一开始声明了float
的精度为中精度,接着和vertex shader
一样有一个main()
方法作为入口,fragment shader
中有一个内置变量gl_FragColor
表示fragment shader
的输出,在之前的例子我们给gl_FragColor
设置了一个固定值vec4(0.0, 0.0, 1.0, 1.0)
,这是一个RGBA
的颜色值,因此我们之前看到的三角形是一个纯蓝色的,现在,我们来实现一个彩色的三角形,这需要vertex shader
和fragment shader
同时修改,来看看我们修改后的shader
:
// vertex shader
precision mediump float;
attribute vec4 a_Position;
attribute vec4 a_Color;
varying vec4 v_Color;
void main() {
v_Color = a_Color;
gl_Position = a_Position;
}
复制代码
// fragment shader
precision mediump float;
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
复制代码
修改后,gl_FragColor
不再是一个固定值,而是一个类型为varying
的颜色值v_Color
,varying
类型变量是一种经过插值后得到的变量,我们可以看到vertex shader
中也声明了同样的varying vec4 v_Color
,然后将a_Color
赋给v_Color
,fragment shader
中的v_Color
就是通过vertex shader
传递过来的,而a_Color
和a_Position
一样是attribute
类型。
上篇文章提到过,vertex shader
会对每个顶点都执行一次,而fragment shader
会对每个像素执行一次,那么fragment shader
中拿到的v_Color
究竟是什么值?它是经过插值的值,这个如何理解呢?先来看一下我们这个例子中传递的值:
// 颜色数据
// The color data
private val colorData = floatArrayOf(
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f)
// 每个颜色的成份数(RGBA)
// The num of components of per color(RGBA)
private val COLOR_COMPONENT_COUNT = 4
// 将三角形顶点数据放入buffer中
// Put the triangle vertex data into the buffer
val colorDataBuffer = ByteBuffer.allocateDirect(colorData.size * java.lang.Float.SIZE)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
colorDataBuffer.put(colorData)
colorDataBuffer.position(0)
// 获取字段a_Color在shader中的位置
// Get the location of a_Color in the shader
val aColorLocation = GLES20.glGetAttribLocation(programId, "a_Color")
// 启动对应位置的参数
// Enable the parameter of the location
GLES20.glEnableVertexAttribArray(aColorLocation)
// 指定a_Color所使用的顶点数据
// Specify the vertex data of a_Color
GLES20.glVertexAttribPointer(aColorLocation, COLOR_COMPONENT_COUNT, GLES20.GL_FLOAT, false,0, colorDataBuffer)
复制代码
我们以与传递三角形顶点给a_Position
相同的方式,将三个颜色值(1.0f, 0.0f, 0.0f, 1.0f)
、(0.0f, 1.0f, 0.0f, 1.0f)
和(0.0f, 0.0f, 1.0f, 1.0f)
传递给a_Color
,这时在vertex shader
执行时会同时取到顶点和颜色数据的同一位置的数据,将这三个颜色值传递给v_Color
后,在fragment shader
中的v_Color
就是经过这三个颜色值插值后的值,例如越靠近颜色(1.0f, 0.0f, 0.0f, 1.0f)
对应的点的地方,颜色就越接近(1.0f, 0.0f, 0.0f, 1.0f)
,我们来看下效果:
代码在我github的OpenGLES2.0SamplesForAndroid
项目中,本文对应的是SampleFragmentShader
,项目链接:github.com/kenneycode/…
感谢阅读!