01- OpenGL ES 学习之绘制三角形

01- OpenGL ES 学习之绘制三角形

前言

几乎学习每种编程语言的第一个项目就是打印一句"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地址

推荐阅读