1.本节学习目标
图形API简介
图形API解决的问题
OpenGL坐标系解析
2.OpenGl学习书籍
3.图形API简介
OpenGL(Open Graphics Library):是一个跨编程语言、跨平台的图形编程程序接口,它将计算机资源抽象成为一个个OpenGL对象,对这些资源的操作抽象为一个个的OpenGL指令。
OpenGL ES(OpenGL for Embedded Systems):是OpenGL三维图形API的子集,针对手机、PDA和游戏主机等嵌入式设备而设计,去除了许多不必要和性能较低的API接口。
DirectX:是由很多API组成的,DirectX并不是⼀个单纯的图形API, 最重要的是DirectX是属于Windows上⼀个多媒体处理框架,并不⽀持Windows以外的平台,所以不是跨平台框架,按照性质分类,可以分为四⼤部分、显示部分、声⾳部分、输⼊部分和⽹络部分。
Metal:Apple为游戏开发者推出的新的平台技术Metal,该技术能够为3D图像提高10倍的渲染性能,Metal是Apple为了解决3D渲染而推出的框架。
虽然苹果推出了Metal框架,但并不表示不用学习OpenGL ES了,因为Metal框架与OpenGL ES的架构是很相似的,因此学习OpenGL ES更有利于我们学习理解Metal框架,而且Metal目前只能应用于苹果设备APP的开发,不具备跨平台的特性。
4.图形API解决的问题
简单来说就是实现图形的底层渲染
⽐如在游戏开发中,对于游戏场景/游戏⼈物的渲染
⽐如在⾳视频开发中,对于视频解码后的数据渲染
⽐如在地图引擎,对于地图上的数据渲染
⽐如在动画中,实现动画的绘制
⽐如在视频处理中,对于视频加上滤镜效果
OpenGL /OpenGL ES/ Metal 在任何项⽬中解决问题的本质:就是利⽤GPU芯⽚来⾼效渲染图形图像,图形API 是iOS开发者唯⼀接近GPU的⽅式.
5.OpenGL专业名词解析
(1)openGL上下文
在应用程序调用任何OpenGL的指令之前,需要首先创建一个OpenGL的上下文。这个上下文是一个非常庞大的状态机,保存了OpenGL中的各种状态,这也是OpenGL指令执行的基础。
OpenGL的函数不管在哪个语言中,都是类似于C语言一样的面向过程的函数,本质上都是对OpenGL上下文这个庞大的状态机中的某个状态或者对象进行操作,当然你得首先把这个对象设置为当前对象,因此,通过对OpenGL指令的封装,是可以将OpenGL的相关调用封装成为一个面向对象的图形API的。
由于OpenGL上下文是一个巨大的状态机,切换上下文往往会产生较大的开销,但是不同的绘制模块,可能需要使用完全独立的状态管理。因此,可以在应用程序中分别创建对个不同的上下文,在不同线程中使用不同的上下文,上下文直接共享纹理、缓冲区等资源。这样的方案,会比反复切换上下文,或者大量修改渲染状态,更加合理高效的。
OpenGL状态机描述了一个对象在其生命周期内所经历的各种状态(状态间的转变,发⽣转变的动因、条件及转变中所执⾏的活动),状态机是⼀种⾏为,说明对象在其⽣命周期中响应事件所经历的状态序列以及对那些状态事件的响应。因此具有以下特点:
有记忆功能,能记住其当前的状态(例如:当前使用的颜色以及是否开启了混合功能等等)。
可以接收输⼊,根据输⼊的内容和⾃⼰的原先状态,修改⾃⼰当前状态,并且可以有对应输出(例如:如我们调⽤glColor3f,则OpenGL接收到这个输⼊后会修改⾃⼰的“当前颜⾊”这个状态)。
当进⼊特殊状态(停机状态)的时候,便不再接收输⼊,停⽌⼯作,在程序退出前,OpenGL总会先停⽌⼯作的。
(2)渲染:将图形图像数据转换为2D空间图像操作叫做渲染(Rendering),通俗点讲就是将图片、视频显示绘制到屏幕上的过程。
(3)顶点数据:画图一般都是先画好图像的骨架,然后再往骨架里面填充颜色,在OpenGL中也是这样,顶点数据就是要画的的图像的骨架,和现实中不同的是,OpenGL中的图像都是由图元组成的。在OpenGL ES中,只有三种类型的图元:点、线和三角形。
(4)顶点数组:将顶点数据存储到内存中后,这部分数据就被成为顶点数组。
(5)顶点缓冲区:提前分配一块显存,将内存中的顶点数据预先传入到GPU显存中(这样做更加高效),这部分的显存,就被称为顶点缓冲区。
(6)位图(纹理):实际上就是将一张png或jpg格式的图片解析为二进制之后得到的数据。(例如:一个120*120分辨率大小的图片,转换为位图就需要 120 * 120 * 4 字节大小的存储空间,一个像素上显示一个颜色需要4字节的空间,主要是因为一种颜色的显示需要RGBA这四种信息,每种信息需要一字节的大小来存储,其中R是三原色中的Red,G是三原色中的Green,B是三原色中的Blue,A是透明度Alpha)
(7)管线:将绘制图片的流程管线,有固定管线和可编程管线,相当于工厂中制造物品的一系列流水线,例如:工程制作各式各样的盆子,不同大小不同的颜色,每种样式都需要相对应的模具来制作,固定管线就相当于这些模具,是工厂定制好的,不可修改只能试用,如果想要自定义样式就需要自己自定义一个模具,而可编程管线相当于自定义模具。
(8)着色器程序Shader :就全面的将固定渲染管线架构变为了可编程渲染管线。因此OpenGl在实际调用绘制函数之前,还需要指定一个由shader编译成的着色器程序。常见的着色器主要有顶点着色器(VertexShader)、片段着色器(FragmentShader)、像素着色器(PixelShader)、几何着色器(GeometryShader)、曲面细分着色器(TessellationShader)。可惜的是,直到OpenGL ES 3.0,依然只支持了顶点着色器和片段着色器这两个最基础的着色器。
OpenGL在处理shader时,和其他编译器一样。通过编译、链接等步骤,生成了着色器程序(GLProgram),着色器程序同时包含了顶点着色器和片段着色器的运算逻辑。在OpenGL进行绘制的时候,首先由顶点着色器对传入的顶点数据进行运算。再通过图元装配,将顶点转换为图元。然后进行光栅化,将图元这种矢量图形,转换为栅格化数据,最后,将栅格化数据转入片段着色器中进行运算,片段着色器会对栅格化数据中的每一个像素进行运算,并决定像素的颜色。如下图所示:
顶点着色器:用来处理顶点数据的代码段(用来确定顶点位置,进行平移、缩放或旋转位置的换算,在屏幕上通过投影换算显示3D图片效果)
片元着色器:用来处理像素点的代码段(例如调整图片饱和度时,片元着色器会对其中每一个像素点都进行处理)
(9)GLSL语言:用来编写自定义着色器代码使用的语言。
(10)光栅化(Rasterization):光栅化是把顶点数据转换为⽚元的过程,具有将图片转化为⼀个个栅格组成的图象的作⽤,特点是每个元素对应帧缓冲区中的⼀像素,进一步讲其实就是⼀种将⼏何图元变为⼆维图像的过程。该过程包含了两部分的⼯作。
第⼀部分⼯作:决定窗⼝坐标中的哪些整型栅格区域被基本图元占⽤。
第⼆部分⼯作:分配⼀个颜⾊值和⼀个深度值到各个区域。光栅化过程产⽣的是⽚元
在物理上是把物体的数学描述以及与物体相关的颜⾊信息转换为屏幕上⽤于对应位置的像素及⽤于填充像素的颜⾊,这个过程称为光栅化,这是⼀个将模拟信号转化为离散信号的过程。
(11)混合(Blending) :在测试阶段之后,如果像素依然没有被踢除,那么像素的颜色将会和帧缓冲区颜色附着上的颜色进行混合,混合的算法可以通过OpenGL的函数进行指定。但是OpenGL提供的混合算法是有限的,如果需要更加复杂的混合算法,一般可以通过像素着色器进行实现,当然性能会比原生的混合算法差一些。例如下图:
其中区域1是红色,区域3是蓝色,两者都是半透明的,区域2是两者混合之后产生的新的颜色,这种颜色不是系统自动帮你合成的,而是需要像素着色器进行混合计算才能产生的。
(12)变换矩阵(Transformation) :例如图形想发⽣平移,缩放,旋转变换.就需要使⽤变换矩阵。
(13) 投影矩阵(Projection):⽤于将3D坐标转换为⼆维屏幕坐标,实际线条也将在⼆维坐标下进⾏绘制。如下图:
(14) 渲染上屏/交换缓冲区(SwapBuffer) :渲染缓冲区一般映射的是系统的资源,比如窗口,如果将图像直接渲染到窗口对应的渲染缓冲区,则可以将图像显示到屏幕上。但是值得注意的是,如果每个窗口只有一个缓冲区,那么在绘制过程中屏幕进行了刷新,窗口可能显示出不完整的图像。如下所示:
为了解决这个问题,常见的OpenGL程序至少都会有两个缓冲区,显示在屏幕上的上称为屏幕缓冲区,没有显示在屏幕上的称为离屏缓冲区。在一个缓冲区渲染完成之后,通过将屏幕缓冲区和离屏缓冲区交换,实现图像在屏幕上的显示。
由于显示器的刷新一般是逐行进行的,因此为了防止交换缓冲区的时候屏幕上下区域的图像分属于两个不同的帧,因此交换一般会等待显示器刷新完成的信号,在显示器两次刷新的间隔中进行交换,这个信号就被称为垂直同步信号,这个技术被称为垂直同步。
使用了双缓冲区和垂直同步技术之后,由于总是要等待缓冲区交换之后再进行下一帧的渲染,使得帧率无法完全达到硬件运行的最高水平,就会出现卡顿(掉帧)的现象。
为了解决这个问题,引入了三缓冲区技术,在等待垂直同步时,来回交替渲染两个离屏缓冲区,而垂直同步发生是,屏幕缓冲区和最近渲染完成的离屏缓冲区交换,实现充分利用硬件性能的目的。
6.OpenGL坐标系解析