因为工作需要,需要了解下OpenGL的基本使用和原理,以及ios下的滤镜框架GPUImage的实现原理,因此在此记录一下。
OpenGL渲染简单流程
在OpenGL中,任何事物都在3D空间中,而屏幕和窗口却是2D像素数组,这导致OpenGL的大部分工作都是关于把3D坐标转变为适应你屏幕的2D像素。
为了描述3D空间中的点,就需要一个三维坐标,一个三维坐标的数组叫做顶点数据(Vertex Data),这些顶点数据描述了需要绘制的图形的点,可以指定这些点渲染成点、线或者三角形。中间经过图元装配阶段、几何着色器处理阶段、光栅化阶段,然后进入片段着色器,来计算一个像素的最终颜色,之后还会经过Alpha测试和混合(Blending)阶段,然后得出最终的像素颜色。
图元装配(Primitive Assembly)阶段将顶点着色器输出的所有顶点作为输入(如果是GL_POINTS,那么就是一个顶点),并所有的点装配成指定图元的形状.
图元装配阶段的输出会传递给几何着色器(Geometry Shader)。几何着色器把图元形式的一系列顶点的集合作为输入,它可以通过产生新顶点构造出新的(或是其它的)图元来生成其他形状。
几何着色器的输出会被传入光栅化阶段(Rasterization Stage),这里它会把图元映射为最终屏幕上相应的像素,生成供片段着色器(Fragment Shader)使用的片段(Fragment)。在片段着色器运行之前会执行裁切(Clipping)。裁切会丢弃超出你的视图以外的所有像素,用来提升执行效率。
大多数情况下,只需要关系顶点着色器和片段着色器的处理即可。在现代OpenGL中,必须定义至少一个顶点着色器和一个片段着色器(因为GPU中没有默认的顶点/片段着色器)。
在iOS环境下使用OpenGL流程
创建自定义view并修改layer
在iOS中一般使用CAEAGLLayer来实现OpenGL的各种功能,一般使用自定义的UIView,并改变他的layer的类型。CAEAGLLayer默认是透明的,官方建议设为不透明。
1 |
|
创建Context上下文
1 |
|
创建render buffer(渲染缓存)
render buffer用来存储即将绘制到屏幕上的图像数据,理解为帧缓冲的一个附件,用来真正存储图像的数据。
1 |
|
创建frame buffer(帧缓冲)
帧缓冲理解为多种缓冲的结合。
1 |
|
创建并编译shader
shader使用着色器语言GLSL(OpenGL Shading Language)编写,主要需要编写顶点着色器和片段着色器的实现,顶点着色器将计算好的顶点传入片段着色器,然后片段着色器计算像素最后的颜色输出。
这里定义两个shader,其中顶点shader直接将顶点坐标传给片段shader,片段shader将像素颜色固定为绿色。shader的具体代码使用NSString字符串常量保存。
1 |
|
接下来需要使用这些字符串常量创建并编译
1 |
|
创建着色器程序并链接shader
着色器程序对象是多个着色器合并之后并最终链接完成的版本。需要将刚才创建的shader链接至着色器程序。
1 |
|
传入顶点数据,完成三角形绘制
1 |
|
最后创建一个自定义view,并在init方法中调用上述方法,即可渲染出三角形。
<img src=”https://i.loli.net/2019/06/15/5d047c69a2de390910.png” alt=”OpenGL01三角.png” title=”OpenGL01三角.png” width=36% />
使用索引缓冲对象
画一个矩形
画一个占据屏幕的矩形,需要两个三角形,也就是6个顶点,可以将之前的顶点坐标数据修改,再将绘制是的顶点数量由3修改为6即可。
1 |
|
<img src=”https://i.loli.net/2019/06/15/5d047c686d22211739.png” alt=”OpenGL01矩形.png” title=”OpenGL01矩形.png” width= 36%/>
这样就会发现,6个顶点中有两个顶点是重复的,如果绘制成千上万个图形,带来的内存开支是非常多的,这时候就可以使用索引缓冲对象,顶点数组存放不重复的顶点,然后将顶点的索引以绘制的形状来存储,可以避免上面的问题。
使用索引绘制
1 |
|
运行之后,也可以显示出绿色的矩形。