【OpenGL】创建窗口(一)

OpenGL 标准库没有提供用于创建窗口和管理窗口的 API,所以要借用其它工具来管理窗口。glut 是一个比较出名的 OpenGL 工具库,用于轻松创建窗口、处理事件、IO 控制和管理设备;可惜的是这个库很久远了,而且已经停止维护了,幸运的是有一个替代库 freeglut,其用法和 glut 基本一样。

没有开始,就永远不会有结果。

使用 glut

OpenGL 标准并没有提供用于创建和管理窗口的 api,各个主流操作系统都提供了支持 OpenGL 的接口,X 系统提供的接口叫做 GLX,Windows 提供的接口叫 WGL,Mac 系统提供的接口叫做 CGL。我们可以使用 OpenGL 的一个工具库 opengl utility toolkit,简称 glut 来管理窗口,处理事件,IO 控制和其它设备管理。

glut 库比较久远,而已已经停止维护了,可使用较新的替代库 freeglut,这两个库的使用方法基本一样。freeglut 下载得到的是源代码,要先使用 cmake 创建工程,然后自己进行编译。

接下来就是配置环境变量了,我使用的环境是 Windows + Visual Studio,这里只介绍系统级的配置。

  • 第一步,把 glut.h 放在 Visual Studio 安装目录下的 VC/include/gl 目录中(默认如果没有 gl 文件夹,自己创建一个);

    基于 VS2012 版本,不同版本位置可能不一样,比如最新的 VS2019 在 VC/Tools/MSVC/14.xxx/include/gl 目录。

  • 第二步,把 glut.lib glut32.lib 放在 Visual Studio 安装目录下的 VC/lib 目录下;
  • 第三步,把 glut.dll glut32.dll 放在系统目录下。

关于 VS 配置的详细内容,可参考 Visual Studio 环境配置

基础库

OpenGL 主要由三个库组成,115 个以 gl 开头的函数组成的 OpenGL 核心库,43 个以 glu 开头的函数组成的 OpenGL 实用库,31 个以 aux 开头的函数组成的 OpenGL 辅助库。另外在 Windows 平台下,有 6 个以 wgl 开头的函数是 Windows 专用库函数,还有 5 个无前缀的函数是 win32api 函数。

OpenGL 核心库,实用库和辅助库,一般 Windows 操作系统都是默认自带的,所以这些函数都可以直接使用。我们下载的工具库函数都是以 glut 开头,平时最常用的函数就是核心库函数 (glFunc),实用库函数 (gluFunc) 和工具库函数 (glutFunc)。

第一个例子

新建一个 C++ 空项目,控制台或 win32 都行,然后添加一个 main.c 源文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <gl/glut.h>

void renderPreFrame();

int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

glutInitWindowPosition(100, 100);
glutInitWindowSize(400, 400);
glutCreateWindow("First Window");

glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glutDisplayFunc(renderPreFrame);
glutMainLoop();

return 0;
}

void renderPreFrame()
{
glClear(GL_COLOR_BUFFER_BIT);
glutSwapBuffers();
}

运行之后可以看到一个 400x400 的黑窗口,在距离左上角 (100,100) 的位置。

first window

分析

  • glutInit 函数用于初始化 glut,其参数可以直接从命令行获取,从命令行启动程序可以带一些有用的参数,比如 -sync 可以关闭 X 异步性质,-gldebug 可以检查 gl 错误并独立地显示它们;
  • glutInitDisplayMode 配置显示模式,GLUT_DOUBLE 设置为双缓冲,即一个缓冲区用于绘制,另一个缓冲区准备着,然后每次渲染两个缓冲区交换,默认设置的是单缓冲 GLUT_SINGLEGLUT_RGBA 指定大多数渲染结束位置(比如屏幕)的颜色模式;
  • glutInitWindowPosition 指定窗口的位置;
  • glutInitWindowSize 指定窗口大小;
  • glutCreateWindow 用于创建窗口,其参数是窗口的标题;
  • glutDisplayFunc 为 OpenGL 的渲染主回调函数;

    glut 提供了一些 OpenGL 与窗口系统交互的函数,glutDisplayFunc 就是其中一个,这个回调函数完成一帧中的所有渲染工作,在 glut 内部循环中不断调用,主回调函数并不会每一帧都绘制,只有窗口发生变化需要重新绘制时才会调用。

  • glClearColor 设置清除帧缓冲时所用的颜色,颜色有四个通道 RGBA,取值范围为 0~1 之间;

    这是一个核心库函数,在这里我们首次接触到 OpenGL 的状态(state),渲染是一个复杂的过程,不能像普通函数一样接受几个参数就能完成功能,它需要指定 shaders,buffers 和其它各种属性,另外几个渲染操作可能使用同样的属性;因此 OpenGL 引入了 state,渲染命令只使用跟绘制顶点个数和初始化偏移值有关的个别属性,其它属性根据当前状态设置;修改状态后,它的值会一直维持不变直到下次修改。

  • glutMainLoop 将程序控制权交给 glut 并开启其内部循环;在这个循环中,它监听来自窗口系统的事件并通过设置的回调函数传递给 glut,最常见的就是我们设置的渲染主函数;glutMainLoop 只会调用一次,调用之后窗口系统就在这里阻塞,将控制权移交给 glut;
  • glClear 使用前面设置的颜色清除帧缓冲;在每次渲染之前,都得先将之前的帧缓冲进行清除;
  • glutSwapBuffers 将前置缓冲和后置缓冲进行交换,这是双缓冲模式调用的函数,如果是单缓冲模式则使用 glFlush 函数。

至此,一个使用 OpenGL 的窗口就创建完成了,这里使用了 2 个核心库函数和 8 个工具库函数,添加了一个回调函数,处理每一帧的渲染工作,在这个回调函数里添加一些绘制图元的函数,就可以在窗口中显示图形了,在下一篇文章就开始干这件事。