OpenGL/OpenGL ES (一) —— 专业名词快速了解
OpenGL/OpenGL ES (二) —— 渲染架构、图元、着色器、投影
OpenGL/OpenGL ES (三) —— 绘制甜甜圈
OpenGL/OpenGL ES (四) —— 纹理
OpenGL/OpenGL ES (五) —— 纹理翻转策略
OpenGL/OpenGL ES (六) —— 立方体旋转
OpenGL/OpenGL ES (七) —— 初探
OpenGL/OpenGL ES (八) —— 如何加载一张图片
OpenGL/OpenGL ES (九) —— 光照
前言
OpenGL ES 是OpenGL三维图形API的子集,方便集成到各个平台。OpenGL是一个跨平台、跨语言的应用程序编程API。它用于绘制从简单图形到复杂的三维景象。PC端的图形图像处理Kit有DirectX,这个需要开发者自己安装的,而GDI和GUI是可以直接调用的。
相关介绍
OpenGL ES 针对那些对内存占用要求比较高的情景使用的,因为它摒弃了glBegin/glEnd,四边形(GL_QUADS)、多边形(GL_POLYGONS)等复杂图元等许多非绝对必要的特性。针对于手机、PDA和游戏主机等嵌入式设备设计。
该API由Khronos集团定义推广,Khronos是一个图形软硬件行业协会,该协会主要关注图形和多媒体方面的开放标准。
OpenGL ES现在主要有两个版本,OpenGL ES 1.x 针对固定管线硬件的,OpenGL ES 2.x 针对可编程管线硬件。
OpenGL ES 1.0 是以 OpenGL 1.3 规范为基础的,OpenGL ES 1.1 是以 OpenGL 1.5 规范为基础的,它们分别又支持 common和 common lite两种profile。lite profile只支持定点实数,而common profile既支持定点数又支持浮点数。
OpenGL ES 2.0 则是参照 OpenGL 2.0 规范定义的,common profile发布于2005-8,引入了对可编程管线的支持。
OpenGL ES 还有一个safety-critical profile。
OpenGL下专业名词解析
OpenGL上下文 context
在应用程序调用任何OpenGL的指令之前,需要先创建一个OpenGL的上下文context。这个上下文是一个非常庞大的状态机,保存了OpenGL中的各种状态,这也是OpenGL指令执行的基础
OpenGL的函数不管在哪个语言中,都是类似C语言一样的面向过程的函数,本质上都是对OpenGL上下文这个庞大的状态机中的某个状态或者对象进行操作,当然你得首先把这个对象设置为当前对象。因此,通过对OpenGL指令的封装,是可以将OpenGL的相关调用封装成为一个面向对象的图形API
*由于OpenGL上下文是一个巨大的状态机,切换上下文往往会产生较大的开销,但是不同的绘制模块,可能需要使用完全独立的状态管理。因此,可以在应用程序中分别创建多个不同的上下文,在不同线程中使用不同的上下文,上下文之间共享纹理、缓冲区等资源。这样的方案,会比反复切换上下文,或者大量修改渲染状态更加合理高效
OpenGL 状态机
- 状态机理论上是一种机器,它描述了一个对象在其生命周期内所经历的各种状态,状态间的转变、发送转变的动因、条件以及转变中所执行的活动。或者说,状态机是一种行为,即对象在其生命周期中响应事件所经历的状态序列以及对那些状态事件的响应。具有一下特点:
1、有记忆功能,能够记住当前的状态
2、可以接收输入,根据输入的内容和自己的原先状态,修改自己当前状态,并且可以有对应输出
3、当进入特殊状态(停机状态)的时候,便不再接收输入,即停止工作
OpenGL中,状态机可以这么理解
1、OpenGL可以记录自己的状态(如当前所使用的颜色、是否开启了混合功能等)
2、OpenGL可以接收输入(调用OpenGL函数时,可以理解成OpenGL在接收输入),如调用glColor3f,即OpenGL接收到这个输入后,会修改自己的“当前颜色”这个状态
3、OpenGL可以进入停止状态,不再接收输入。在程序退出前,OpenGL总会先停止工作
渲染
- 将图形/图像数据转换成3D空间图像操作叫做渲染(Rendering)
顶点数组VertexArray和顶点缓冲区VertexBuffer
- 顶点: 指的是在绘制一个图形时,它的顶点位置数据,而这个数据可以直接存粗在数组中或者将其缓存到GPU内存中
- OpenGL中的图像都是由图元组成,在OpenGL ES中,有3种类型的图元:点、线、三角形。开发者可以选择设定函数指针,在调用绘制方法的时候,直接由内存传入顶点数据,也就是说这部分数据之前是存储在内存当中的,被称为顶点数组。而性能更高的做法是提前分配一块显存,将顶点数据预先传入到显存当中,这部分的显存,就被称为顶点缓冲区
管线
- 管线:可以理解为渲染流水线。实际上指一堆原始图形数据途径一个输送管道,期间经过各种变化处理最终出现在屏幕的过程。
- 在OpenGL下渲染图形,就会经历一个一个节点。而这样的操作可以理解为管线。可以想象成流水线,每个任务类似流水线一样执行,任务之间有先后顺序。之所以称之为管线是因为显卡在处理数据的时候是按照一个固定的顺序来的,而且严格按照这个顺序。就像水从一根管子的一端留到另一端,这个顺序不能打破。
- 固定管线:简单理解为渲染图像这个过程,我们只能通过调用GLShaderManager类的固定管线效果实现一系列的着色器处理。
- 可编程管线:简单理解为在处理图形的过程,我们能够使用自定义顶点着色器和片元着色器的过程。由于OpenGL的使用场景非常丰富,固定管线或者存储着色器无法完成每一个任务,这时将相关部分开放成可编程
着色器程序Shader
- 将固定渲染管线架构变成为可编程渲染管线。因此,OpenGL在实际调用绘制函数之前,还需要指定一个由shader编译成的着色器程序。常见的着色器主要有顶点着色器(VertexShader)、片段/片元着色器(FragmentShader)/像素着色器(PixelShader)、几何着色器(GeometryShader)、曲面细分着色器(TessellationShader)。知道OpenGL ES3.0,依然只支持了顶点着色器和片段着色器这两个最基础的着色器
- OpenGL在处理shader时,和其他编译器一样。通过编译、链接等步骤,生成了着色器程序(glProgram),着色器程序同时包含了顶点着色器和片元着色器的运算逻辑。在OpenGL进行绘制的时候,首先由顶点着色器对传入的顶点数据进行运算。在通过图元装配,将顶点转换为图元。然后进行光栅化,将图元这种矢量图形,转换为栅格化数据。最后,将栅格化数据传入片元着色器中进行运算。片元着色器会对栅格化数据中的每一个像素进行运算,并决定像素的颜色。
顶点着色器VertexShader
- 一般用来处理图形每个顶点变换(旋转/平移/投影等)
- 顶点着色器时OpenGL中用于计算顶点属性的程序。顶点着色器是逐顶点运算的程序,也就是说每个顶点数据都会执行一次。当然这是并行,并且顶点着色器运算过程中无法访问其他顶点数据
- 一般来说典型的需要计算的顶点属性主要包括顶点坐标变换、逐顶点光照运算等等。顶点坐标由自身坐标系转换到规范化坐标系的运算,就是在这里发生的
片元着色器FragmentShader
一般用来处理图形中每个像素点颜色计算和填充
片元着色器是OpenGL中用于计算片段(像素)颜色的程序,片元着色器是逐像素运算的程序,也就说每个像素都会执行一次片元着色器,当然也是并行的
GLSL (OpenGL Shading Language)
- OpenGL着色语言是用来在OpenGL中着色编码的语言,也就是开发人员写的短小的自定义程序,他们是在GPU(Graphic Processor Unit图形处理单元)上执行的,代替了固定的渲染管线的一部分,使渲染管线中不同层次具有可编程性。
- GLSL的着色器代码分成2个部分: VertexShader(顶点着色器) 和 Fragment Shader(片元着色器)
光栅化 Rasterization
- 光栅化就是把顶点数据转换为片元的过程。具有将图转化为一个个栅格组成的图像的作用。片元中的每一个元素对应于帧缓冲区的一个像素
- 光栅化其实是一种将几何图元变为二维图像的过程。该过程包含了两部分的工作。第一部分工作:决定窗口坐标中的哪些整型栅格区域被基本图元占用;第二部分工作:分配一个颜色值和一个深度值到各个区域。光栅化过程产生的是片元
- 把物体的数学描述以及与物体相关的颜色信息转换为屏幕上用于对应位置的像素以及用于填充像素的颜色,这个过程称为光栅化,这是一个将模拟信号转化为离散信号的过程
纹理
- 纹理可以理解为图片。在渲染图形时需要在其编码填充图片,为了使得场景更加逼真,而这里使用的图片,就是常说的纹理。在OpenGL中,更加习惯叫纹理,而不是图片。
混合 Blending
- 在测试阶段之后,如果像素依然没有被剔除,那么像素的颜色将会和帧缓冲区中颜色附着上的颜色进行混合。混合的算法可以通过OpenGL的函数进行指定。但是OpenGL提供的混合算法有限的,如果需要更加复杂的混合算法,一般可以通过像素着色器进行实现,当然性能会比原声的混合算法差一些
- 混合就是把两种颜色混在一起。具体一点,就是把某一像素位置原来的颜色和将要画上去的颜色,通过某种方式混在一起,从而达到特殊的效果
变换矩阵 Transformation
- 图形想发生平移、缩放、旋转变换,就需要使用变换矩阵
投影矩阵 Projection
- 用于将3D坐标转换为二维屏幕坐标,实际线条也将在二维坐标下进行绘制
渲染上屏/交换缓冲区 SwapBuffer
渲染缓冲区一般映射的是系统的资源,比如窗口。如果将图像直接渲染到窗口对应的缓冲区,则可以将图像显示到屏幕上。但是,值得注意的是,如果每个窗口只有一个缓冲区,那么在绘制过程中,屏幕进行了刷新,窗口可能显示出不完整的图像。
常规的OpenGL程序至少都会有两个缓冲区。显示在屏幕上的称为屏幕缓冲区,没有显示的称为离屏缓冲区。在一个缓冲区渲染完成之后,通过将屏幕缓冲区和离屏缓冲区交换,实现图像在屏幕上显示。
因为显示器的刷新一般是逐行进行的,因此为了防止交换缓冲区的时候,屏幕上下区域的图像分属于两个不同的帧,因此交换一般会等待显示器刷新完成的信号,在显示器两次刷新的间隔中进行交换,这个信号就被称为垂直同步信号,这个技术被称为垂直同步
使用了双缓冲区和垂直同步技术之后,由于总是要等待缓冲区交换之后再进行下一帧的渲染,使得帧率无法完全达到硬件允许的最高水平,为了解决这个问题,引入了三缓冲区技术,在等待垂直同步时,来回交替渲染两个离屏的缓冲区,而垂直同步发生时,屏幕缓冲区和最近渲染完成的离屏缓冲区交换,实现充分利用硬件性能的目的