常用的图形处理框架有OpenGL
、OpenGL ES
、DirectX
和Metal
。OpenGL
是一个跨平台的图形程序接口;OpenGL ES
是OpenGL
三维图形API的子集,它去除了许多不必要和性能较低的API,主要是真的手机、游戏主机等嵌入式设备而设计的;DirectX
是Windows平台上处理多媒体的API,它并不是一个单纯的图形API;Metal
是苹果2014年新推出的3D渲染框架,它能将3D图像渲染性能提高10倍。本文主要介绍图像处理中(主要是OpenGL)涉及到的一些常用专业名称。
1. OpenGL的上下文(Context)
在我们调用OpenGL的指令之前,需要先创建一个上下文,这个上下文中保存了OpenGL的各种状态和需要操作的对象,执行OpenGL指令实际上就是对上下文中的某个状态或者对象进行操作。
根据实际需求,可在应用程序中创建1个或多个上下文,在不同线程中使用不同的上下文,上下文间共享纹理、缓冲区等资源。
2. 渲染(Rendering)
将图像数据(一组3D坐标)转换成屏幕和窗口中2D的有颜色的像素的操作就叫做渲染。
3. 顶点(Vertex)、顶点数组(VertexArray)和顶点缓冲区(VertexBuffer)
- 顶点
不管是2D图像还是3D图像,图像的轮廓(或者说图像的骨架更合适)都是由一些特殊的点连线组成,这些特殊的点就叫顶点,比如一个四方形有4个顶点,一个四方体有8个顶点。有人可能会有疑问,四边形五边形这些图形的顶点好理解,但是向圆形这样的图形也有顶点吗?是的,我们可以想象一下,如果我们用4个点把一个圆周等分成4分,然后把这4个点连起来就是一个正方形,如果用8个点等分连起来就是一个正八边形,如果是20个点的话就是正20边形,我们会发现等分的点越多,这些点连起来的图像就越接近圆,所以可以理解为这些点就是圆的顶点。
- 顶点数组
在使用OpenGL时,开发者在绘制图像之前会将图像的顶点数据存入一个数组中,这个数组就是顶点数组,它是存在内存中的。在调用绘制方法时直接去内存中取这些顶点数据进行绘制。
- 顶点缓冲区
为了提高性能,会提前分配一块显存,将顶点数据预先传入显存中,这部分显存区域就被称为顶点缓冲区。
4. 管线
在OpenGL渲染图形时,从3D坐标数据转换成2D有颜色的像素并不是一步完成的,这中间经历了很多个步骤,这些步骤是有先后顺序的,这就像生成车间一样,首先将原料(3D坐标数据)进行第一步加工处理,然后将加工过的半成品输送到第二个环节进行第二步加工处理,第二步加工后的半成品又送到第三个环节进行加工,一直到最后一个环节加工完成变成成品(2D有颜色的像素),这整个流程就像是一条生成流水线一样,我们称之为管线。
5. 着色器(Shader)
着色器是运行在GPU上的程序,它的主要用途是对三维物体进行着色处理,对光与影进行计算,以及控制纹理颜色的呈现等。从上面的渲染管线流程图可以看出在图形渲染过程中用到了多种着色器,包括顶点着色器、细分着色器、集合着色器、片元着色器等。其中顶点着色器和片元着色器是2个最基本的着色器。
- 顶点着色器(VertexShader)
顶点着色器是用于计算顶点属性的程序,主要包括顶点坐标转换、顶点关照运算等等。每个顶点都是单独运算的,也就是说每个顶点数据都会执行一次顶点着色器(并行执行)。
- 细分着色器(TessellationjShader)
细分着色器由细分控制着色器)和细分赋值着色器完成。它会收到来自顶点着色器输出的数据,并对收到的数据进行进一步的处理,它会在OpenGL管线内部生成新的几何体。(这是一个可选阶段)
- 几何着色器(GeometryShader)
它会在OpenGL管线内部对所有几何图元进行修改,可以选择输入图元生成更多的几何体,改变几何图元的类型(比如将三角形转化成线段),或者放弃所有的几何体。(这是一个可选阶段)
- 片元着色器(FragmentShader)
片元着色器又叫像素着色器或片段着色器,主要用来处理图形中每个像素点(经过光栅化后得到的片元)的颜色计算和填充。每个像素点都会执行一次片元着色器。通常,片元着色器包含3D场景的数据(比如光照、阴影、光的颜色等等),这些数据可以被用来计算最终像素的颜色。
6. 图元装配(Primitive Setup)
图元装配就是将顶点和与之相关的几何图元组织起来,准备下一步的剪切和光栅化工作
7. 裁剪
由于顶点可能会出现在窗口显示区域之外,所以要进行裁剪操作来丢弃超出视图以外的所有像素。
8. 光栅化(Rasterization)
光栅化就是把顶点数据转换成片元的过程。通俗点讲就是通过顶点来确定在窗口中图形由哪些像素点构成,以及每个像素点要分配什么颜色(一个像素点就是一个片元)。经过光栅化后得到的片元交给片元着色器计算确定片元最终颜色和它的深度值。
9. 纹理(Texture)
纹理本质上就是图片,我们在渲染图形时需要填充颜色,如果我们自定义颜色进行填充往往会色调单一,缺乏真实感,此时如果用实物照片作为参考,采用照片中的颜色和透明度的排列方式来渲染,渲染处理的图形就会更加逼真。这里作为参考的图片就是常说的纹理。
10. Alpha测试
经过片元着色器处理并经过裁剪后,会进入Alpha测试阶段,这个阶段会检测片元的对应的深度,以此来判断这个像素是其它物体的前面还是后面,决定是否应该丢弃。这个阶段也会检查alpha值(alpha值定义了一个物体的透明度)。
11. 混合(Blending)
在测试阶段之后,如果像素依然没有被剔除,那么像素的颜色将会和帧缓冲区中颜色进行混合,混合的算法可以通过OpenGL的函数进行指定。但如果需要更加复杂的混合算法,⼀般可以通过像素着⾊器来实现,当然性能会比原⽣的混合算法差一些。
12.变换矩阵(Transformation)和投影矩阵(Projection)
- 图形想发⽣平移、缩放、旋转等变换就需要使⽤变换矩阵。
- 投影矩阵用于将3D坐标转换为二维屏幕坐标,实际图像也将在二维坐标下进行绘制。
13. 交换缓冲区(SwapBuffer)
交换缓冲区就是将屏幕缓冲区
和离屏缓冲区
进行交换。CPU将计算好的需要显示的内容提交给GPU,GPU渲染完成后将渲染结果放入帧缓冲区
(一个缓冲区存储一帧的数据),屏幕就是通过读取帧缓冲区的数据,然后逐行扫描显示在屏幕上,当整个屏幕都显示完后,在准备新一轮的扫描之前会发送一个垂直同步信号
,然后从帧缓冲区读取下一帧的数据进行显示,从而刷新屏幕。但是如果在发送垂直同步信号时由于某些原因(比如下一帧的图像渲染比较耗时)导致CPU或GPU还没来得及将新的数据提交到帧缓冲区,那这一帧就会被丢弃,屏幕还是显示原理的图像,这就造成了卡顿掉帧的现象。
如果只有一个缓冲区的话,在缓冲区完全展示之前GPU是不能提交新的数据的,那就意味着GPU需要等待,这样就会造成性能浪费。为了提高性能,这时我们可以重新开辟一段缓冲区来存储GPU新提交的内容,这一段新的缓冲区就是离屏缓冲区
,而屏幕当前显示的缓冲区就是屏幕缓冲区
。当收到垂直同步信号时,就需要将屏幕缓冲区
和离屏缓冲区
进行交换,也就是之前的离屏缓冲区变成了现在的屏幕缓冲区,之前的屏幕缓冲区变成了离屏缓冲区,然后GPU再次提交数据就是提交到新的离屏缓冲区。