OpenGL 一 - 002、图形 API 的简单介绍 + 专有名词解析
One:图形API的简单介绍
1)图形API
1、OpenGL(Open Graphics Library) ,一门跨平台、跨编程语言的程序接口。一个标准,用来调度GPU处理事情的。
OpenGL主要是针对PC端(Mac、Windows)的。
2、OpenGL ES(OpenGL for Embedded System),ES = 嵌入式。它是 OpenGL 三维图形API的子集,可理解为比OpenGL少了一些API(许多不必要的和性能较低的API)
针对 移动端的,手机端安卓iOS系统、PDA(一般指掌上电脑)、游戏主机等嵌入式设备而设计,他去除了许多不必要的和性能较低的API。
A、OpenGL/OpenCV 两者区别简单介绍:
a、OpenGL主要做渲染 --> 显示位图 -->按钮图片等的显示都会以位图的形式处理,它们的显示就用到了OpenGL。
b、OpenCV主要用来识别,人脸识别、卡号识别、物体识别等(OpenCV face++:付费商用) --> 与人工智能的结合。
3、DirectX :由很多API组成,它并不是单纯的图形API,它是只支持Windows平台的一个多媒体处理框架,非跨平台框架,按性质可分为:显示部分、声音部分、输入部分、网络部分四大部分。
4、Metal :Apple为了解决3D渲染而推出的框架。游戏开发者的新的技术平台,该技术能够为3D图像提高 10 倍的渲染性能。苹果底层渲染是由Metal来实现的。
上图,苹果核心动画 CoreAnimation,是基于OpenGL/Metal的高级封装,调 CoreAnimation 的时候其实就是在调度 OpenGL/Metal 来完成GPU的驱动。(2018年以前是OpenGL,后面就是Metal了)
2)图形API是干什么的?
解决渲染问题。
OpenGL/OpenGL ES/Metal 在任何项目中,解决问题的本质就是,利用GPU芯片来高效渲染图形图像。图形API是iOS开发者唯一接近GPU的方式。
1、系统针对按钮图片,视图、图层渲染问题
2、游戏引擎 --> 任务/场景渲染
3、视频播放框架 --> 视频解码(ijkplayer、kxmovie) --> 渲染
4、核心动画
5、视频/图片 --> 特效
6、离屏渲染(待续...)
Two: 专有名词介绍
一、OpenGL 上下文【context】
在应用程序调用任何OpenGL的指令前,需要首先创建一个OpenGL的上下文。这个上下文是一个很庞大的状态机,保存了OpenGL中的各种状态,这些也是OpenGL指令执行的基础。
OpenGL的函数不论在哪个语言环境下,都是类似于C的面向过程的函数,本质都是对OpenGL上下文中的 某个状态or某个对象 进行操作。自然,这个对象首先是需要设置为当前对象的,因此,通过对OpenGL指令的封装,是可以将OpenGL的相关调用封装为一个面向对象的图形API 的。
OpenGL上下文是一个巨大的状态机,切换上下文时会产生较大的开销,但不同的绘制模块可能需要使用完全独立的状态管理,因此,可以在应用程序中,针对不同模块,分别创建多个不同的上下文,在不同线程中使用不同上下文,上下文之间共享纹理(位图)、缓冲区等资源。这样,相较于频繁的切换上下文or大量修改渲染状态,更加合理高效有条理。
二、OpenGL 状态机
1)首先理解 状态机是什么???
状态机理论上是一种机器,可以理解为:记录了一堆 某个对象在其生命周期内所经历的各种状态,状态之间的转变,转变的动因、转变的条件,转变中执行的活动。====>>>> (借鉴百度知道的例子:人有三个状态:健康,感冒,康复中。触发的条件有淋雨(t1),吃药(t2),打针(t3),休息(t4)。所以状态机就是健康-(t4)->健康;健康-(t1)->感冒;感冒-(t3)->健康;感冒-(t2)->康复中;康复中-(t4)->健康,等等。就是这样状态在不同的条件下跳转到自己或不同状态的图)。
状态机是一种行为,说明对象在其生命周期中 响应事件所经历的状态序列 以及 对那些状态事件的响应。它具有下面特点:
A、有记忆功能,记录住当前的状态
B、可以接收输入,根据输入内容和自己原先的状态,修改当前状态,病可以有对应的输出
C、当进入特殊状态(停机状态)时,不再接收输入,停止工作。
2)OpenGL状态机:类推过里可以这样理解:
A、OpenGL可以记录自己的状态(当前的使用的颜色、是否开启了混合功能等)
B、OpenGL可以接收输入(当调用OpenGL函数时,可以看成是OpenGL在接收我们的输入),例如,我们调用 glColor3f,则OpenGL接收到这个输入后就会修改自己的‘当前颜色’这个状态。
C、OpenGL可以进入停止状态,不再接收输入。在程序退出前,OpenGL总会先停止工作。
三、渲染(Rendering):将 图形/图像数据转换成 2D 空间图像的操作,叫做渲染
四、顶点数组(VertexArray)和顶点缓冲区(VertexBuffer)
类比,做一张图,首先画图像的骨架,之后再往里填充颜色。OpenGL的顶点数据就是要画的图像的骨架,OpenGL的图像都是由图元组成的。在OpenGL ES中,由3中类型的图元:点、线、三角形。如下图,绘制一个长方形的图片,要首先要知道绘制在屏幕的哪个位置,因为OpenGL没有长方形一说,所以是被分割成2个三角形的,它有6个顶点(不规则图形相通的就是有多个顶点),这6个顶点数据存储在哪里呢?(何为顶点?指在绘制一个图形时,他的顶点位置数据。)
顶点数组存储有2种方式:
顶点数组:顶点数据存储在内存中,被称为顶点数组。没那么高效
顶点缓冲区:更加快速的被GPU拿到,顶点数据存储到GPU的显存中来,这部分显存则被称为顶点缓冲区。
(要显示的PNG图片,前提是此图片已解压成位图了,PNG --解压--> 位图 ,coreGraphic,PNG对应的位图大小:120*120 --> RGBA -> 每个占8位 == 4个字节 --> 14400 * 4)
纹理(位图)坐标只关乎到映射,对应关系,图像的绘制就是点对点的映射关系。
五、管线
流水线,在OpenGL下渲染图形,会经历像流水线工作的一个个节点,这样的操作可以理解为管线。类似流水线,每一个任务都像生产流水线似的执行,任务之间是有先后顺序。
为何叫管线?显卡在处理数据的时候是严格按照一个固定的顺序来的,像一个水管,一端流到另一端,顺序是不可打破的。
1)固定管线/存储着色器(固定着色器):
特定模具,提供了很多着色器,只能调用固定的 API,不可自定义。
在早起的OpenGL版本,封装了很多种,着色器 程序块 内置的,一段包含了光照、坐标变换、裁剪等诸多功能的,固定shader程序,来完成 帮助开发者完成图形的渲染,只需要传入相应的参数就可以完成图形的渲染。类似iOS中封装的一堆API们,我们只调用。
2)可编程管线:
可自定义编程的模具。
由于OpenGL的使用场景非常丰富,固定管线或存储着色器无法完成每一个业务,此时,相关一部分 开放成可编程,可基于GLSL语法进行一些编写。
五(2)、着色器程序 Shader (自定义)
类似于一个函数/方法,它是给GPU用的。
1、为全面的将固定渲染管线架构变成可编程渲染管线。OpenGL在实际调用绘制函数之前,还需要制定一个由 shader 编译承德着色器程序。
常见的着色器:
顶点着色器(VertexShader)、
片元/片段着色器(FragmentShader)/像素着色器(PixelShader)、 --> // 两者知只是在 OpenGL 和 DX中的不同叫法;
几何着色器(GeometryShader)、
曲面细分着色器(RessellationShader)。
2、OpenGL 在处理 shader 时,和其他编译器一样。通过编译、链接等步骤,生成着色器程序(glProgram),着色器程序同时包含了 顶点着色器和片元着色器的运算逻辑。
在 OpenGL 进行绘制时,首先由顶点着色器对传入的顶点数据进行运算 --> 再通过图元装配、将顶点转换为图元 --> 然后进行光栅化,将图元这种事量图形转化为栅格化数据 --> 最后,将栅格化数据传入 片元着色器 中进行运算。 --> 片元着色器会对栅格化数据中的每一个像素进行运算,并决定像素的颜色。
着色器渲染过程:
渲染过程中,必须存储 2 种着色器:顶点着色器、片元着色器;顶点着色器处理顶点数据,片元着色器处理像素点颜色。
有且仅有顶点着色器和片元着色器我们可触碰到。
1)顶点着色器(VertexShader):
OpenGL中用来处理顶点相关的程序代码,一般用来处理图形每个顶点变换:
-->1、确定位置;2、旋转缩放平移;3、投影换算:手机端显示3D屏幕(实际还是2D),3D图形数据 --> 2D投影换算
2)片元着色器(FragmentShader)
片元其实就是指像素,Fragment翻译成片元只是个名字而已,所以片元着色器也被叫做 像素着色器。
用来处理一个个像素点的,处理图形中每个像素点颜色的计算和填充。片元着色器是逐像素运算的程序,即:每个像素都会执行一次片元着色器(并行的)。120*120的PNG图片转换成位图--> 要计算14400次,但是对GPU并行运行来说来说就不算多是小case。
六、GLSL(OpenGL Shading Language)
一门语言,OpenGL着色语言,是用来在OpenGL中 着色编程的语言,遵循OpenGL的规则,来调动GPU做运算的语言。
开发人员编写的自定义程序,它是在图形卡的GPU上执行的,替代了固定的渲染管线的一部分,是渲染管线中不同层次具有可编程性。比如:试图转换、投影转换等。GLSL的着色器代码分2个部分:顶点着色器、片元着色器。
七、光栅化
核心动画的属性里有个属性就是打开光栅化 --> shouldRasterize(光栅化)是比较特别的一种离屏渲染。
光栅化是把 顶点数据转化成片元数据的过程,(光栅化不可编程),把图转化成由一个个栅格组成的图像,每个元素对应帧缓冲区的一像素。参照上面的图一。
光栅化的2个过程:1、确定图形的像素范围(在哪个位置) 2、计算好的颜色附着上去。物理过程,我们可操作的就只有顶点和片元着色器。
八、纹理
可以理解为图片,在OpenGL中的图片并非pngJPG图片,而是位图图片,在OpenGL中称之为纹理。 .tga纹理文件
九、混合(Blending)
例:layer有2个图层,一个粉色有透明度,一个蓝色有透明度,两个layer叠加在一起会有个混合的颜色,这个混合行为是需要 混合计算 的,混合运算。
混合的算法可以通过OpenGL的函数进行指定。但OpenGL提供的混合算法是有限的,需要更加复杂的混合算法,可通过像素着色器实现,但是当然性能方面会比原生的混合算法差些。
十、矩阵
1)变换矩阵(Transformation):
图形想要发生平移、缩放、旋转变换,需要一个变换矩阵。例如旋转一个三角形,每个顶点都要进行一定的旋转,这个旋转就对应一个变换矩阵。
图形 * 变换矩阵(旋转/缩放/平移)
2)投影矩阵(Projection):
用于3D坐标转换为一个二维2D坐标。