文章目录
- OpenGL概述
- OpenGL的本质
- OpenGL相关库
- 核心库
- 窗口管理
- glut
- freeglut
- glfw
- 函数加载
- glew
- GLAD
OpenGL概述
OpenGL(Open Graphics Library) 严格来说,本身并不是一个API,它是一个由Khronos组织制定并维护的规范(Specification)。OpenGL规范严格规定了每个函数该如何执行,以及它们的输出值。至于内部具体每个函数是如何实现(Implement)的,将由OpenGL库的开发者自行决定。
实际上OpenGL的大多数实现都是由显卡厂商编写的,即一系列可以操作图形、图像的API。当产生一个bug时通常可以通过升级显卡驱动来解决。这些驱动会包括你的显卡能支持的最新版本的OpenGL。
这里科普一下Khronos组织,由Intel、Nvidia等公司共同创立,致力于创建开放标准的应用程序API。OpenGL、OpenGL ES、WebGL、Vulkan都是来自Khronos。而Vulkan称为“下一版本的OpenGL”,旨在提供更低的CPU开销和更多GPU控制。Android API 24以后支持Vulkan,iOS在WWDC2014也推出Metal。
Windows平台常用绘图引擎
Vulkan与OpenGL对比——Vulkan的全新渲染架构
OpenGL有两套API
- 核心模式(Core-profile)
也叫做可编程管线,提供了更多的灵活性,更高的效率,更重要的是可以更深入的理解图形编程。 - 立即渲染模式(Immediate mode)
也叫做固定渲染管线,早期OpenGL使用的模式。大多数功能都被库隐藏起来,容易理解和使用,但是灵活性和效率太低。
从OpenGL3.2开始,规范文档开始废弃立即渲染模式,并鼓励开发者在OpenGL的核心模式(Core-profile)下进行开发
这与 GPU 的发展历史有关,最初的 GPU 是不能编程的,也叫固定管线,就是把数据按照固定的通路走完,后来发展出了可编程的 GPU,也叫可编程管线,一开始只能用汇编写 GPU 程序,然后进一步发展出了 GPU 高级编程语言,也就是现在所说的着色语言(Shading Language)。
了解了 GPU 的发展历史就明白为什么 OpenGL 会有两套 API 了。立即渲染模式 就是最初 GPU 不能编程时的 API,核心模式 则是使用了着色语言的现代 API。
最新版本的 OpenGL 对立即渲染模式也是支持的,故而也把立即渲染模式称为兼容模式。
OpenGL - The Industry Standard for High Performance Graphics
LearnOpenGL文档
OpenGL的本质
As long as you keep in mind that OpenGL is bsically one large state machine, most of its functionality will make more sense.
OpenGL自身是一个巨大的状态机(state machine)
- 即变量(描述该如何操作)的大集合。
- OpenGL的状态通常别称作
上下文(context)
- 状态设置函数(State-changing Function)
- 状态应用函数(State-using Function)
通过改变一些上下文变量来改变OpenGL的状态,从而告诉OpenGL如何绘图。
- 一个对象(Object)是指一些选项的集合,代表OpenGL状体的一个子集。可以把对象看作一个C风格的结构体。
struct object_name { GLfloat option1; GLuint option2; GLchar[] name; };
- 上下文(Context)往往看作是包含很多对象的大的结构体。
struct OpenGL_Context { object* object_window_target; ... };
OpenGL相关库
核心库
Windows平台上,OpenGL相关库已经包含在Windows SDK里了。
项目中链接opengl32.lib
库,并包含相关头文件使用:
#include <gl/GL.h>
#include <gl/GLU.h>
窗口管理
窗口操作在每个系统上都是不一样的,OpenGL 有目的地将这些操作抽象(Abstract)出去。
这意味着我们不得不自己处理创建窗口,定义 OpenGL 上下文以及处理用户输入。
幸运的是,有一些库已经提供了我们所需的功能。这些库节省了我们书写操作系统相关代码的时间,提供给我们一个窗口和上下文用来渲染。
glut
GLUT - The OpenGL Utility Toolkit
所有 glut 的库函数均以 glut 开头,主要包括窗口操作函数,窗口初始化、窗口大小、窗口位置等函数;回调函数:响应刷新消息、键盘消息、鼠标消息、定时器函数等;创建复杂的三维物体;菜单函数;程序运行函数。
但是版本太老了,理应被时代淘汰,不推荐使用。gult 最后版本 v3.7beta 的历史可追溯至 1998 年 8月,且该项目已经被废弃。它的许可证禁止任何人发布修改后的库代码。
freeglut
FreeGLUT
gult 对应的开源实现,完全兼容 glut,是 glut 的代替品,开源,功能齐全。
glfw
GLFW - Graphics Library Framework
lightweight轻量化的 OpenGL 框架,一个头文件,很少量的 API,就完成了窗口管理。glfw 的开发目的是用于替代 glut 的,从代码和功能上来看,它已经完全的完成了任务。它是一个轻量级的,开源的,跨平台的library。支持 OpenGL 及 OpenGL ES,用来管理窗口,读取输入,处理事件等。
freeglut与glfw的区别
最大的区别是,在处理用户输入上,FreeGLUT主要通过回调函数(Callback
function),而GLFW则提供了两种输入机制即回调函数与轮询(polling)。在回调函数方式 中,用户提供给GLFW的回调函数用来处理用户输入操作如键盘按键或鼠标操作。
当用户按下或者松开按键时,它都会被触发,包括一些特殊的键位(例如 Shift、Caps Lock、Esc等)。
而在轮询方式中,程序可以直接查询系统中是否已经按下了任意键,或者更具体一点,是否按下了某个特定的键。
它允许用户直接获取某个按键的瞬时状态,相当于用户直接询问:“这个键现在被按下了吗?”
回调函数与轮询这两种方式的最大差别,轮询方式能连续获得键盘输入,而回调函数则适用于按键速度不是特别快,不需要连续效果(比如人物不停地跑),具体可参考这篇文章。
另外,freeglut支持创建右键菜单,而GLFW不支持。
GLFW在输入机制上提供了更多选择,同时也增加了复杂性。
而freeglut则相对较为简单,因此如果从学习OpenGL与图形学的角度来看,freeglut不失为一个合适的选择。而如果对程序的连续性输入要求较高时,则可以考虑GLFW。
函数加载
OpenGL 只是一个标准/规范,具体的实现是驱动开发商针对特定显卡实现的。
由于 OpenGL 驱动版本众多,它大多数函数的位置都无法在编译时确定下来,需要在运行时查询。
所以任务就落在了开发者身上,开发者需要在运行时获取函数地址并将其保存在一个函数指针中供以后使用。
这个过程非常复杂,而且很繁琐,需要对每个可能使用的函数都要重复这个过程。幸运的是,有些库能简化此过程。
是对底层OpenGL接口的封装,可以让代码跨平台。
glew
GLEW - The OpenGL Extension Wrangler Library
前面已经说过openGL的实现是显卡生产商,那么系统如何才能找到这些实现好的函数呢?而且不同的平台函数存放地方还不同,文件结构也不同。有没有一种方式能够自动找到OpenGL的函数?这就是glew的作用:用来找openGL的函数,并初始化,这样我们就能直接调用OpenGL的函数了。
GLAD
glad是继gl3w,glew之后,当前最新的用来访问OpenGL规范接口的第三方库。简单说glad是glew的升级版。
GLAD是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前我们需要初始化GLAD。GLAD也可以使OpenGL基础渲染变得简单。
https://glad.dav1d.de/
选择对应的OpenGL版本和Core模式下载。
include目录添加进VS工程的附加包含目录。
src目录中的glad.c文件需要添加进项目目录。
#include <glad/glad.h>
需要注意的是
要先包含glad后包含glfw
#include <glad/glad.h> #include <GLFW/glfw3.h>
MFC程序中添加glad.c时不能用预编译头。
因为 .cpp 项目且添加了glad.c文件后,项目中混合了 .cpp 和 .c文件,由于编译器对它们采取不同的编译方式因此出错。因而不能共用一个预编译头文件。在 VC++ 中,默认的预编译头文件是针对 C++ 的(stdafx.h 和 stdafx.cpp)。
如果要使用预编译头文件,可以将glad.c改为glad.cpp并添加#include "stdafx.h"