前言
几乎学习每种编程语言的第一个项目就是打印一句"Hello world",接下来用一个Hello_triangle程序来展示如何绘制一个三角形到屏幕上,在这个程序中,你将了解到OpengGL ES的工作过程。也将对它有一个大致的了解。
绘制三角形demo
参考书籍:OPENGL ES 3.0编程指南 原书第2版
后续的文章都将参考该书籍,里面有详细讲解各个部分,是学习OpenGL ES不可多得的指导资料,后面都将简称该书,后文中将OpenGL ES简称为ES。示例代码中的程序都是基于Xcode13创建的。
在分析代码步骤前,我们先看一下ES的渲染流程
大致的流程图如下
从图中可以看出,最开始的输入是顶点数据。比如一个三角形,就是传入三个顶点。每个顶点数据可以包含任意数量的信息,最基本的有顶点位置,颜色。后面介绍贴图时还会包含UV信息。经过顶点着色器,图元装配,光栅化,片段着色器,逐顶点操作,帧缓冲区,这里使用双缓冲区的方案,所有渲染发生在后台缓冲区,它位于不可见于屏幕的内存区域,当所有渲染完成时,这个缓冲区被“交换”到前台缓冲区(可见于屏幕的缓冲区),然后前台缓冲区编程下一帧的后台缓冲区,如此交替往复,完成渲染。
这个demo程序中包含了两种写法,一种是使用了GLKit(内部封装了一部分ES的api,更便于开发者高效地编写ES应用程序),并且使用了数组缓冲区对象,这种方法使得ES应用程序可以再高性能的图形内存中分配和缓存顶点数据,并从这个内存进行渲染,从而避免在每次绘制图元的时候重新发送数据,可以显著地改进渲染性能,也会降低内存带宽和电力消耗的需求,对于手持设备相当重要,ES 3.0推荐应用这种方式。
另一种是没有使用GLKit,而是使用的ES的原生API,这有助于你理解ES的工作过程。而且没有使用缓冲区对象,使用的是客户空间(ES将应用程序地址空间称为客户空间),这里你可以和使用了缓冲区对象作对比,以便于了解两种方式的不同。
下面将讲解示例中的未使用GLKit的例子
对应上面的图示,主要的渲染步骤如下
第一步,提供顶点数据
这里是顶点数据用数组表示,里面包含三个,三分量的向量,对应的就是(x,y,z)来表示每个顶点的位置
typedef struct {
GLKVector3 positionCoords;
}SceneVertex;
static const SceneVertex vertices[] = {
{{-0.5f,-0.5f,0.0f}},
{{0.5f,-0.5f,0.0f}},
{{-0.5f,0.5f,0.0f}},
};
第二步,顶点着色器
demo先用字符数组来保存着色器,实际开发中最好是放在单独的文件中,通过加载文件来加载着色器。
//顶点着色器
char vShaderStr[] =
"#version 300 es \n"
"layout(location = 0) in vec4 vPosition; \n"
"void main() \n"
"{ \n"
" gl_Position = vPosition; \n"
"} \n";
第三步,图元装配
glDrawArrays(GL_TRIANGLES, 0, 3);
这一步,以形状为单位汇总渲染指令,demo中是绘制三角形,还可以通过glDrawArrays命令绘制点和直线,ES只支持绘制 点,直线 ,三角形 三种基本图元。
第四步,光珊化
这一步会栅格化绘制的形状。第一步我们说过只需传递顶点的颜色,两点中间的颜色ES会帮我们处理。ES将会计算出每一个像素对应的属性,比如颜色,这些值都是根据顶点的属性值以及形状计算而来的。具体绘制的效果如下图:
第五步,片段着色器
经过栅格化之后,每一个像素都要经片段着色器处理一遍。以后图片的滤镜等效果都是在这个里面来实现的。下面是demo中的片段着色器。
//片段着色器
char fShaderStr[] =
"#version 300 es \n"
"precision mediump float; \n"
"out vec4 fragColor; \n"
"void main() \n"
"{ \n"
" fragColor = vec4 ( 0.0, 1.0, 0.0, 1.0 ); \n" //这里设置颜色为绿色
"} \n";
第六步, 逐顶点操作
这里主要是对像素的一些固定操作,比如 颜色测试,模板测试,深度测试等等
第七步 绘制到帧缓冲区
这里的工作GLKit帮我们完成了.
这里还有一个需要讲清楚,就是ES 的屏幕坐标系
这里屏幕中间是原点(0,0,0),z轴是垂直于屏幕表面的。
实践是检验真理的唯一标准,可以下载demo,自己按照步骤来写从而加深理解。
最后推荐大佬写的视频编码解码库----》github地址