一、OpenGL简介
- OpenGL是一种用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程规范。
- OpenGL包含一系列可以操作图形和图像的函数,但OpenGL没有实现这些函数,OpenGL仅规定每个函数应该如何执行以及其输出值(类似接口),所以OpenGL仅是一种严格的规范。
- OpenGL规范严格规定了每个函数该如何执行,以及它们的输出值。至于内部具体每个函数是如何实现(Implement)的,将由OpenGL库的开发者自行决定。实际的OpenGL库的开发者通常是显卡的生产商。
- OpenGL被设计为只有输出的,所以它只提供渲染功能。核心API没有窗口系统、音频、打印、键盘/鼠标或其他输入设备的概念。虽然这一开始看起来像是一种限制,但它允许进行渲染的代码完全独立于他运行的操作系统,所以OpenGL允许跨平台开发。
- OpenGL没有提供着色器编译器,而是由显卡驱动来完成着色器的编译工作,也就是说,只要显卡驱动支持对GLSL的编译它就能运行,所以OpenGL能够跨平台。
- 核心模式与立即渲染模式:
早期OpenGL使用立即渲染(Immediate mode,也就是固定渲染管线)容易使用和理解,但是效率太低。从OpenGL3.2开始废弃立即渲染模式,鼓励使用核心模式(Core-profile)。
核心模式:要求使用者真正理解OpenGL和图形编程,有一些难度,然而提供了更多的灵活性,更高的效率,可以更深入理解图形编程。 - 扩展:
OpenGL的一大特性就是对扩展(Extension)的支持,当一个显卡公司提出一个新特性或者渲染上的大优化,通常会以扩展的方式在驱动中实现。 - 状态机:
OpenGL自身是一个巨大的状态机(State Machine):一系列的变量描述OpenGL此刻应当如何运行。OpenGL的状态通常被称为OpenGL上下文(Context)。我们通常使用如下途径去更改OpenGL状态:设置选项,操作缓冲。最后,我们使用当前OpenGL上下文来渲染。 - 对象:
OpenGL库是用C语言写的,同时也支持多种语言的派生,但其内核仍是一个C库。由于C的一些语言结构不易被翻译到其它的高级语言,因此OpenGL开发的时候引入了一些抽象层。“对象(Object)”就是其中一个。
使用对象的一个好处是在程序中,我们不止可以定义一个对象,并设置它们的选项,每个对象都可以是不同的设置。在我们执行一个使用OpenGL状态的操作的时候,只需要绑定含有需要的设置的对象即可。
二、OpenGL程序
众所周知程序是运行在CPU上的,程序代码处于内存之中,在我们通常的理念中一般仅涉及CPU和内存,而使用OpenGL的渲染程序却有所不同,其涉及了GPU和显存,如下图所示:
从内存到显存
- 我们的程序运行在CPU上,程序的数据储存在内存之中。
- 当我们需要渲染一个场景时,可能需要场景中物体的一些顶点数据、纹理数据、着色器参数等。这些数据是我们程序指定的,它们最初存储于外存中,当我们程序在CPU运行时我们将它们读入内存中。
- 显卡中有显存,这个缓冲区可以存储图形缓冲、深度缓存、纹理、顶点缓存等一系列渲染场景所需要的数据。利用这些数据,执行GPU的渲染指令,即可渲染我们想要的场景。
- 那么问题来了,我们如何将内存中的数据传输到显存呢?
- 毫无疑问这一切的答案都在OpenGL中,通过OpenGL有关函数,我们运行在CPU上的程序可以向显存中发送数据,将渲染场景所需的数据存储于显卡的显存缓冲区中。
OpenGL渲染状态机
- 当渲染所需数据已经传输到显存中时,我们如何执行GPU的渲染命令呢?
- GPU的渲染指令是非常底层的,涉及显卡类型等硬件参数,这样复杂的指令让我们去调用是不可能的。但是我们有OpenGL。
- 渲染是一套固定的流程,我们无法对接GPU的底层指令,那我们是否可以建立一个通用的、无关硬件的渲染模型呢?当然可以,这就是OpenGL。
- 渲染是一个流程,这个过程中拥有很多可设置的选项,我们称这些选项为OpenGL的状态。所谓状态机,即拥有众多参数作为状态,当在不同的状态情况下会做出不同的反应,例如在不同的场景选项下呈现出不同的渲染结果。
- OpenGL是一个完整的渲染状态机,Khronos组织制定并维护了OpenGL,换句话说:他们建立了OpenGL的状态机模型。这个模型是用于渲染的,它包含很多参数作为状态。针对这个模型,Khronos组织制定了OpenGL应该包含的函数,这些函数包括一些状态设置函数(State-changing Function)和状态应用函数(State-using Function)。使用状态设置函数可以改变OpenGL上下文即OpenGL的状态,使用状态应用函数会根据当前OpenGL的状态执行一些操作。
- 如简介所说,OpenGL只是一个规范并没有具体的函数实现。如上文所说,OpenGL只是一个包含许多状态的渲染模型,其制定了一整套渲染所需的函数规范。那么我们如何搭建起OpenGL这个数学模型和GPU底层渲染指令间的桥梁呢?即OpenGL制定的函数该由谁实现呢?这通常是显卡开发商该思考的,显卡开发商针对OpenGL模型规范,开发出具体显卡的OpenGL驱动程序,即在特定的OpenGL的状态下,显卡会执行特定的渲染指令。
- 如此一来,我们只需要和OpenGL这个通用的、和硬件无关的状态机进行交互,即可执行出我们所需的GPU渲染指令。而程序和OpenGL的交互无非是改变OpenGL的状态,例如设置OpenGL的选项,或操作缓冲区、或执行渲染操作。
三、GLFW和GLEW
书接上文,OpenGL只提供渲染功能,核心API中没有创建窗口、键盘监听等输入概念,那么我们要进行渲染,肯定要把渲染后的画面呈现的电脑的窗口上,这该怎么办呢?
使用GLFW即可,GLFW是一个跨平台的OpenGL应用框架,支持窗口创建,接受输入和事件等功能。其成员以GLFW形式开头。
上文中提到扩展,当我们想要使用一个OpenGL函数时,需要查询当前平台是否支持这个函数,并且返回这个函数的指针。这毫无疑问是一件非常麻烦的事情,那么有什么方便的途径吗?
使用GLEW即可,GLEW是一个基于OpenGL图形接口的跨平台的C++扩展库。GLEW能自动识别当前平台所支持的全部OpenGL高级扩展涵数。只要包含glew.h头文件,就能使gl,glu,glext,wgl,glx的全部函数。GLEW支持目前流行的各种操作系统。其成员常常以gl开头。
四、其他
本文参考并引用参考文章内容。
本文内容仅为个人在OpenGL学习中的感想,如有不当之处请不吝赐教。