万丈高楼平地起,OpenGL中专有名词对初学者来说是入门阶段较为晦涩难懂的主要原因之一,但却是我们必须要反复推敲理解,融会贯通的重要部分。本文针对OpenGL以及图形渲染中一些专有名词进行解析,加入了一些自己的理解(本文暂不针对OpenGL具体函数/API)。
一、OpenGL状态机
状态机描述了一个对象在其生命周期内所经历的各种状态,状态间的转变,发生转变的动因,条件及转变中所执行的活动。或者说,状态机是一种行为,说明对象在其生命周期中响应事件所经历的状态序列以及对那些状态事件的响应。因此具有以下特点:
- 1.有记忆功能,能记住其当前的状态;
- 2.可以接收输入,根据输入的内容和自己的原先状态,修改自己当前状态,并且可以有对应输出;
- 3.当进入特殊状态(停机状态)的时候,变不再接收输入,停止工作;
【举例】通俗的说,例如一个电视机,我们打开后,电视机开始播放。播放的状态则会持续,下一次再按,就是关闭。而当电视机处于关闭状态时,我们切换频道,加减声音都是无效的。因为不再接受数据。OpenGL既是如此,当我需要混合的时候,开启混合->计算混合色值->绘制->关闭混合。是一个完整的流程,如果我们开启了不关闭,OpenGL会一直记录混合开启状态。这也是我们在OpenGL中见到很多状态切换语句 ,最典型像什么glEnable ,glDisable, 还有就是设置语句. glTexImage2d, glBindXXX, glUseProgram 等.. 抽象来说它里面就是一堆参数在来回切换来切换去.
而事实上如何切换也是一门学问,切不好 绘制结果出现问题,而且很影响效率。
二、OpenGL上下文【context】
-
读完上面,我们知道了OpenGL是个状态机。此时我们先提一句OpenGL的设计模式。我们可以将整个OpenGL系统分为两部分,一部分是客户端,它负责发送OpenGL命令。一部分是服务端,它负责接收OpenGL命令并执行相应的操作。比如我们编写的程序就是一个客户端,而我们的计算机图形硬件制造商提供的OpenGL的实现就是服务器。
-
我们可以认为每一个硬件GPU是个服务器,每一个绘制上下文对应于申请的一个客户端,一个客户端维护着一套状态机,如果两个窗口分别对应两个不同的绘制上下文,则两个窗口彼此状态独立。申请绘制上下文,意味着系统资源的申请,每个绘制上下文还是需要不少资源的。
-
在应⽤用程序调⽤用任何OpenGL的指令之前,需要安排⾸首先创建⼀一个OpenGL的 上下⽂。这个上下⽂是一个非常庞大的状态机,保存了了OpenGL中的各种状 态,这也是OpenGL指令执行指令的基础。
使用glut创建上下文示例:
glutInitContextVersion(3,3);
glutInitContextProfile(GLUT_CORE_PROFILE);
//glutInitContextFlags(GLUT_FORWARD_COMPATIBLE); //设置forward compatibility
三、渲染
- 渲染:将图形/图像数据转换成3D空间图像操作叫做渲染(Rendering).
四、顶点缓冲区/顶点数组对象(VBO/VAO)
顶点的概念我就不多赘述了,那么顶点缓冲区呢?
-
显示列表可以快速简单地优化立即模式(glBegin/glEnd)的代码。在最坏的情况下,显示列表的命令被预编译存到命令缓冲区中,然后发送给图形硬件。在最好的情况下,是编译后放在图形硬件中以减少传输的带宽。显示列表的优化根据实现的不同而有所不同,而且显示列表一旦被创建就不可以修改,灵活性差。
-
顶点数组提供了我们想要的灵活性,最坏的结果不过是把数据块复制给硬件而已(比立即模式快的多)。而索引顶点数组可以减少向硬件传输的顶点数据的数量,减少变换的开销。
OpenGL提供了一个特性对图形的吞吐量进行终极的控制。当我们使用顶点数组时,可以把单个数组从客户内存(CPU可以访问)传输到图形硬件。这个特性称为顶点缓冲区对象,允许我们按照类似于管理纹理的方式来管理顶点数组数据,而且顶点缓冲区对象要更灵活。
简单的来说:
OpenGL3.0之前的设置顶点方法,在glBegin和glEnd之间使用。已经废弃此方法。每个glVertex与GPU进行一次通信,十分低效。
glBegin(GL_TRIANGLES);
glVertex(0, 0);
glVertex(1, 1);
glVertex(2, 2);
glEnd();
而VBO/VAO是CPU提供给GPU的顶点信息,包括了顶点的位置、颜色(只是顶点的颜色,和纹理的颜色无关)、纹理坐标(用于纹理贴图)等顶点信息,减少了与GPU通讯,加快效率。
这里推荐一篇博客,关于这个问题讲解的很详细。
http://www.cnblogs.com/BigFeng/p/5117311.html
五、管线 Graphics Pipeline
管线总结为:顶点数据(Vertices) > 顶点着色器(Vertex Shader) > 图元装配(Assembly) > 几何着色器(Geometry Shader) > 光栅化(Rasterization) > 片断着色器(Fragment Shader) > 逐片断处理(Per-Fragment Operations) > 帧缓冲(FrameBuffer)。再经过双缓冲的交换(SwapBuffer),渲染内容就显示到了屏幕上。而管线指的就是这个流程,一般这个流程我们在OpenGL中使用ShaderManager来管理。
OpenGL中有两种管线:
- 一种为固定管线,已封装好的一个渲染流程。(OpenGL最新标准(4.0或更高)明确删除了固定管线功能)
-
另一种为可编程管线,这个可编程管线中加载了着色器程序Shader。OpenGL中的Shader和其他编译器一样需要通过编译,链接等步骤,生成着色器语言glProgram,着色器程序包含着色器的运算逻辑。
简单介绍,每个部分做了什么事情
六、顶点着色器Vertex Shader和片元(片段/像素)着色器Fragment Shader
先通俗理解他们是干啥的。
- 着色器(Shader)。画画的时候我们经常有这么一个过程:先打线稿,再上色。着色器就是用来做这个工作的。通常着色器分两种:
1.顶点着色器(vertex shader)这个是告诉电脑如何打线稿的——如何处理顶点、法线等的数据的小程序。
2.片元着色器(fragment shader)(片段/像素)为不同翻译,本文统称片元着色器这个是告诉电脑如何上色的——如何处理光、阴影、遮挡、环境等等对物体表面的影响,最终生成一副图像的小程序。采用了这两种着色器小程序 的 数据传输处理计算的渲染过程,称之为 可编程管线。
顶点着色器一般用来处理每个顶点变换(旋转,平移,投影等),顶点着色器是OpenGL中用来处理计算顶点属性的程序。
片元着色器是OpenGL中用于计算片段,即每一个像素颜色的程序,参考上图(简单介绍那张图)也就是说每个像素都会执行一次片元着色器。
(叫做程序比较好关联理解因为可编程管线中我们可以自己修改计算逻辑。也就是GLSL,下面这条会将)
七、GLSL(OpenGL Shading Language)
OpenGL着色语言是用来在OpenGL中着色编程的语言,开发者可自己编写以代替固定管线流程的一部分,既是可编程管线。GLSL分为顶点着色器和片元着色器两个部分。
GLSL其使用C语言作为基础高阶着色语言,避免了使用汇编语言或硬件规格语言的复杂性。
八、光栅化Rasterize/Rasteriztion
光栅化(像素化)是把已有的顶点数据转化为片元的过程,具有将图像转化为一个个格栅组成的图像的作用。特点是每个元素对应帧缓冲区中的一个像素。
通俗理解就是把矢量图形转化成像素点儿的过程。我们屏幕上显示的画面都是由像素组成,而三维物体都是点线面构成的。要让点线面,变成能在屏幕上显示的像素,就需要Rasterize这个过程。就是从矢量的点线面的描述,变成像素的描述。
如下图,这是一个放大了1200%的屏幕,前面是告诉计算机我有一个圆形,后面就是计算机把圆形转换成可以显示的像素点。这个过程就是Rasterize。
九、纹理
纹理可以理解为图片,图像渲染时经常需要填充图片。这里的图片其实就是纹理,在OpenGL中,我们更喜欢称之为纹理 。
- 常见图像文件格式(BMP,TGA,JPG,GIF,PNG)
- 常见纹理格式(R5G6B5,A4R4G4B4,A1R5G5B5,R8G8B8, A8R8G8B8等)
十、混合(Blending,Blend)
- 混合是一种常用的技巧,通常可以用来实现半透明。但其实它也是十分灵活的,你可以通过不同的设置得到不同的混合结果,产生一些有趣或者奇怪的图象。
混合是什么呢?混合就是把两种颜色混在一起。具体一点,就是把某一像素位置原来的颜色和将要画上去的颜色,通过某种方式混在一起,从而实现特殊的效果。 - 举例:假设我们需要绘制这样一个场景:透过红色的玻璃去看绿色的物体,那么可以先绘制绿色的物体,再绘制红色玻璃。在绘制红色玻璃的时候,利用“混合”功能,把将要绘制上去的红色和原来的绿色进行混合,于是得到一种新的颜色,看上去就好像玻璃是半透明的。
要使用OpenGL的混合功能,只需要调用:glEnable(GL_BLEND);即可。
要关闭OpenGL的混合功能,只需要调用:glDisable(GL_BLEND);即可。
注意:只有在RGBA模式下,才可以使用混合功能,颜色索引模式下是无法使用混合功能的。
十一、变换矩阵
OpenGL中视图变化通常有两种方式:
- 第一种是更改物体位置,而这种方法也有两种方式
1.直接更新顶点,使用copyVertexData更新视图顶点位置,重新渲染。
2.通过矩阵相乘更新仿射变换记录,通过更新模型视图变换矩,重新渲染。 - 第二种是更新坐标系
关于OpenGL中多种坐标系和变换原理本文不多阐述,参考该系列下一篇博客。
OpenGL坐标系解析(顶点从对象坐标系到屏幕坐标系的计算流程)
(本文非转载,如转载请标明来源,谢谢)
网友评论