前言
网上很多介绍OpenGL ES的文章,但由于OpenGL ES内容太多,所以这些文章难免过于臃肿杂乱,很难抓住重点,对于初学者来说最后还是云里雾里。很多人(包括笔者本人)开始深入了解OpenGL ES是因为其涉及到实时滤镜的应用,通常都会参考开源框架GPUImage的实现。如果没有掌握基本的OpenGL Es的开发知识,很难弄懂其中代码缘由。
目前很流行的短视频特效处理也有涉及到OpenGL的应用,于是已经踩坑无数的笔者下决心让后来者少走弯路,以最实用的场景——显示一张图片开始学习OpenGL ES.
本文章适合初学Android OpenGL ES 2.0+,以及想要了解OpenGL实时滤镜实现原理的同学。
准备
在开始实现之前,先要讲一些基本的知识,也是OpenGL ES 2D\3D绘图的一些基本理论,这里我们只讲绘制一张图片后面需要用到的知识点。
坐标系
OpenGL拥有独立的坐标系,没有任何变换前的初始坐标系为三维坐标系,x y z 取值范围都是 [-1, 1]:
由于我们绘制的是2D图片,因此可以简化为二维坐标系(只包含xy轴),坐标系的原点在窗口中央,x 轴向右,y 轴向上:
这时就有疑问了,我们的屏幕或显示窗口长宽的比例不是1:1(即不是正方形),怎么跟OpenGL的初始世界坐标系对应呢?如果我们没有指定投影比例,那么世界坐标系则会填充整个显示窗口,这样就会导致拉伸变形,比如把上面的三角形投射在窗口时的显示如下:
如果要指定投影比例就得应用到投影和矩阵变换,这里我们仍使用初始的世界坐标系,比如为了上面的三角形显示正常,根据拉伸比例改变绘制的顶点坐标即可。
顶点坐标
在OpenGL ES中,支持三种类型的绘制:点、直线以及三角形;由这三种图形组成其他所有图形,比如我们看到的圆滑的球体也是由一个个三角形组成的,三角形越多看上去越圆滑:
在绘制图形时我们需要提供相应的顶点位置,然后指定绘制方式去绘制这些顶点,以此呈现出我们想要的图形。
后面我们显示一张图片的时候也需要绘制由两个三角形组成的矩形,通过GL_TRIANGLE_STRIP绘制方式(即每相邻三个顶点组成一个三角形,为一系列相接三角形构成)绘制:
纹理贴图(纹理映射)
我们需要显示的是一张图片,而上面一直说绘制图形。这就好比我们往墙上贴墙纸,首先得搭建好房子,然后决定墙纸的每个地方贴在墙上的哪个位置,这个过程在OpenGL的绘制过程中叫做纹理贴图,也叫纹理映射。
纹理贴图时涉及到UV坐标,所有的图像文件都是二维的一个平面,通过这个平面的UV坐标我们可以定位图象上的任意一个象素,在android的uv坐标的原点在左上角:
我们根据顶点的渲染顺序,定义每个顶点uv坐标,如下图是我们定义的四个顶点,绘制成一个矩形:
那么根据顶点的渲染顺序,定义每个顶点uv坐标:
指定好特定顶点对应的纹理坐标后,顶点与顶点间的其