一、什么是OpenGL
OpenGL (Open Graphics Library)是一个跨编程语言、跨平台的编程图形程序接口,也就是“图形硬件的一种软件接口”。
二、OpenGL专有名词
-
OpenGL Context(上下文)
-
OpenGL是个
状态机
,采用了客户端 - 服务端
模式,把每一个绘制上下文对应于申请的一个客户端,每一个硬件GPU对应于一个服务器,一个客户端维护着一套状态机,它保存了OpenGL中的各种状态,是OpenGL指令执行的基础。 -
由于切换上下文往往会产生较大的开销,而不同绘制模块可能需要使用完全独立的状态管理。因此,可以在应用程序中分别创建多个不同的上下文,在不同线程中使用不同的上下文,上下文之间共享
纹理
、缓冲区
等资源。这样,会比反复切换上下文,或者大量修改渲染状态,更加合理高效。 -
使用OpenGL中的API,其实也就是对上下文中某个状态或者对象进行操作。因此,通过对OpenGL指令的封装,可以将OpenGL的相关调用封装成一个面向对象的图形API。
-
-
状态机
-
状态机是理论上的一种机器。它描述了一个对象在其生命周期内所经历的各种状态,状态间的转变,发生转变的动因,条件及转变中所执行的活动。它具有以下特点:
-
有记忆功能,能记住其当前的状态;
-
可以接收输入,根据输入的内容和自己的原先状态,修改自己当前状态,并且可以有对应输出;
-
当进入特殊状态(停机状态)的时候,便不再接收输入,停止工作。
-
-
-
OpenGL状态机
-
相对应的,OpenGL状态机有以下特点:
-
OpenGL可以记录自己的状态(如当前所使用的颜色、是否开启了混合功能等)。
-
OpenGL可以接收输入(当调用OpenGL函数的时候,实际上可以看成OpenGL在接受我们的输入)。如:我们调用
glColor3f
,则OpenGL接收到这个输入后会修改自己的当前颜色
这个状态。 -
OpenGL可以进入停止状态,不再接收输入。在程序退出前,OpenGL总会先停止工作。
-
-
-
渲染
将图形/图像数据转换成3D空间图像的操作就叫做渲染(Rendering)。
-
管线
-
在OpenGL 下渲染图形,就会有经历一个一个节点。而这样的操作可以理解为管线,就像流⽔线一样,每个任务类似流水线般按顺序执行。
-
管线是⼀个抽象的概念,之所以称之为管线是因为显卡在处理数据的时候是按照⼀个固定的顺序来的,⽽且严格按照这个顺序。就像⽔从一根管⼦的一端流到另一端,这个顺序是不能打破的。
-
OpenGL有两种管线:固定管线和可编辑管线。
-
-
着色器 (Shader)
-
图形渲染管线接收一组3D坐标,然后把它们转变为你屏幕上的有色2D像素输出。
-
图形渲染管线可以被划分为几个阶段,每个阶段将会把前一个阶段的输出作为输入。所有这些阶段都是高度独立化的(它们都有一个特定的函数),并且很容易并行执行。
-
正是由于它们具有并行执行的特性,当今大多数显卡都有成千上万的小处理核心,它们在GPU上为每一个(渲染管线)阶段运行各自的小程序,从而在图形渲染管线中快速处理你的数据。这些小程序叫做着色器(Shader)。
-
-
顶点着色器(VertexShader)
-
一般用来处理图形每个顶点变换(旋转/平移/投影等)。
-
顶点着色器是OpenGL中用于计算顶点属性的程序。每个顶点都会并行的执行一次顶点着色器,并且顶点着色器运算过程中无法访问其他顶点的数据。
-
顶点坐标变换、逐顶点光照,以及顶点坐标由自身坐标系转换到归一化坐标系等的运算,就是在这里发生的。
-
-
片元(段)着色器(FragmentShader)
-
一般用来处理图形中每个像素点颜色计算和填充。
-
片元着色器是OpenGL中用于计算片段(像素)颜色的程序。每个像素都会执行一次片元着色器,当然也是并行的。
-
-
OpenGL着色器语言(OpenGL Shading Language, GLSL)
- OpenGL着⾊器语言是用来在OpenGL中着色编程的语⾔,即开发人员写的短⼩的自定义程序,他们是在图形卡的 GPU (Graphic Processor Unit图形处理理单元)上执行的,代替了固定的渲染管线的⼀部分,使渲染管线中不同层次具有可编程性。比如:视图转换、投影转换等。GLSL 的着色器代码分 2 个部分:Vertex Shader(顶点着⾊器)和Fragment(片段着⾊器)。
-
图元(Primitive)
-
为了让OpenGL知道我们的坐标和颜色值构成的到底是什么,OpenGL需要你去指定这些数据所表示的渲染类型。我们是希望把这些数据渲染成一个点?一个三角形?还是仅仅是一个长长的线?做出的这些提示叫做图元(Primitive),任何一个绘制指令的调用都将把图元传递给OpenGL。
-
常用的图元有以下几种:
-
GL_POINTS
-
GL_LINES
-
GL_LINE_STRIP
-
GL_LINE_LOOP
-
GL_TRIANGLES
-
GL_TRIANGLE_STRIP
-
GL_TRIANGLE_FAN
-
-
-
图元装配(Primitive Assembly)
- 将顶点着色器输出的所有顶点作为输入(如果是GL_POINTS,那么就是一个顶点),并将所有的点装配成指定图元的形状的阶段就叫做图元装配。
-
几何着色器(Geometry Shader)
- 图元装配阶段的输出会传递给几何着色器(Geometry Shader)。几何着色器把图元形式的一系列顶点的集合作为输入,它可以通过产生新顶点构造出新的(或是其它的)图元来生成其他形状。
-
光栅化(Rasterization)
-
就是把顶点数据转换为片元的过程,具有将图转化为一个个栅格组成的图象的作用,特点是每个元素对应帧缓冲区中的一像素。
-
光栅化其实是一种将几何图元变为⼆维图像的过程。该过程包含了两部分的⼯作。第⼀部分工作:决定窗⼝坐标中的哪些整型栅格区域被基本图元占⽤用;第二部分⼯作:分配一个颜色值和一个深度值到各个区域。光栅化过程产⽣的是片元。
-
把物体的数学描述以及与物体相关的颜色信息转换为屏幕上用于对应位置的像素及用于填充像素的颜色,这个过程称为光栅化,这是一个将模拟信号转化为离散信号的过程。
-
-
纹理(Texture)
- 纹理可以理解为图片。在渲染图形时需要在其编码填充图片,为了使得场景更加逼真,而这里使用的图片,就是常说的纹理
-
混合(Blending)
- 在测试阶段之后,如果像素依然没有被剔除,那么像素的颜色将会和帧缓冲区中颜色附着上的颜色进行混合,混合的算法可以通过OpenGL的函数进行指定。但是OpenGL提供的混合算法是有限的,如果需要更加复杂的混合算法,一般可以通过像素着色器进行事先,当然性能会比原生的混合算法差一些。
-
变换矩阵(Transformation)
- 例如图形想发生平移、缩放、旋转变换,就需要使用变换矩阵。
-
投影矩阵(Projection)
- 用于将3D坐标转换为二维屏幕坐标,实际线条也将在二维坐标下进行绘制。
-
渲染上屏/交换缓冲区(SwapBuffer)
-
渲染缓冲区一般映射的是系统的资源,比如:窗口。如果将图像直接渲染到窗口对应的渲染缓冲区,则可以将图像显示到屏幕上。
-
但是,值得注意的是,如果每个窗口只有一个缓冲区,那么在绘制过程中屏幕进行了刷新,窗口可能显示出不完成的图像。
-
为了解决这个问题,常规的OpenGL程序至少都会有两个缓冲区。显示在屏幕上的称为屏幕缓冲区,没有显示的称为离屏缓冲区。在一个缓冲区渲染完成之后,通过将屏幕缓冲区和离屏缓冲区交换,实现图像在屏幕上的显示。
-
由于显示器的刷新一般是逐行进行的,因此为了防止交换缓冲区的时候屏幕上下区域的图像分属于两个不同的帧,因此交换一般会等待显示器刷新完成的信号,在显示器两次刷新的间隔中进行交换,这个信号就被称为垂直同步信号,这个技术被称为垂直同步。
-
使用了双缓冲区和垂直同步技术之后,由于总是要等待缓冲区交换之后再进行下一帧的渲染,使得帧率无法完全达到硬件允许的最高水平。为了解决这个问题,引入了三缓冲区技术,在等待垂直同步时,来回交替渲染两个离屏的缓冲区,而垂直同步发生时,屏幕缓冲区和最近渲染完成的离屏缓冲区交换,实现充分利用硬件性能的目的。
-
三、OpenGL 投影方式
- OpenGL有两种投影方式:透视投影、正投影,如下图:
-
正投影(平行投影):使用正投影时,需要指定一个正方形/长方形的视景体。 在视景体以外的任何物体都不会被绘制,并且使用正投影所以实际大小相同的物体在屏幕上都具有相同的大小。不管它们是否存在远近问题,正投影比较适合平面图形/2D图形渲染时使用。
-
透视投影:它在3D开发中更为常见。同样需要指定视景体的,而这个视景体并不是类似于正方体,看起来像平截体。 透视投影一般会使用于3D图像渲染,因为它会更加逼真。
四、OpenGL图形渲染流程
- 下图,是一个图形渲染管线的每个阶段抽象展示
网友评论