前言
本文在 Manjaro Linux
下进行操作,学习如何在 Linux
下结合 CMake
搭建 OpenGL
环境。
编译GLFW
我们在绘制图形的时候,需要创建一个 OpenGL
上下文和一个窗口,处理用户的输入,这些操作在每个操作系统上都不一样, OpenGL
将这些操作抽象出去,所以这些工作就需要程序员自己来做了。不过好消息是已经有第三方库做了这件事情了,比如 GLUT
、 SDL
、 SFML
、 GLFW
。这里我们选用 GLFW
。
下面的步骤教大家编译一个 GLFW
的静态库。
1
2
3
4
5
|
git clone https://github.com/glfw/glfw.git
cd glfw
mkdir build && cd build
cmake ..
make
|
执行完以上步骤会在 build/src
目录下看到 libglfw3.a
这个静态库,这个文件后面会要用到。
GLAD
前面我们说道 OpenGL
是一个规范,它由驱动厂商针对特定的显卡实现的, OpenGL
驱动的版本众多,它的函数位置无法在编译时确定下来,需要在运行时查询。这件事同样落在了开发者身上,同样幸运的是已经第三库做了就是GLAD。打开这个网址选择如下所示
点击 generate
后,会把 glad.zip
下载到本地,解压得到 src
和 include
两个目录,如下所示
1
2
3
4
5
6
7
8
|
.
├── include
│ ├── glad
│ │ └── glad.h
│ └── KHR
│ └── khrplatform.h
└── src
└── glad.c
|
这里只有头文件,我们不需要进行编译,后面直接引入项目中使用即可。
创建一个项目
资源都准备好了,就可以开始创建项目了,执行如下命令
1
2
3
|
mkdir window && cd window
mkdir src include lib
touch CMakeLists.txt src/main.cpp
|
我们把 glfw
中 include
文件夹下的 GLFW
拷贝到刚刚创建的 include
目录下,并且把 GLAD
中 include
的 glad
和 KHR
两个目录也拷贝到刚刚创建的 include
目录下。
接着把 glfw/build/src
中的 libglfw3.a
拷贝到刚刚创建的 lib
目录下。
最后把 glad/src/glad.c
拷贝到刚刚创建的 src
目录下。
目录拷贝完了之后,我们还要在根目录下创建 CMakeLists.txt
文件,并且在 src
下新建 main.cpp
作为程序的入口文件。
整个目录如下所示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
.
├── CMakeLists.txt
├── include
│ ├── glad
│ │ └── glad.h
│ ├── GLFW
│ │ ├── glfw3.h
│ │ └── glfw3native.h
│ └── KHR
│ └── khrplatform.h
├── lib
│ └── libglfw3.a
└── src
├── glad.c
└── main.cpp
|
编写 CMake
文件都准备好了,我们来编写 CMakeLists.txt
,导入 GLFW
静态库和 GLAD
的头文件,和添加依赖。如下所示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
cmake_minimum_required(VERSION 3.12)
project(window)
set(CMAKE_CXX_STANDARD 14)
# 添加头文件所在的目录
include_directories(${PROJECT_SOURCE_DIR}/include)
# 导入 glfw 静态库
add_library(glfw STATIC IMPORTED)
set_target_properties(glfw PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/lib/libglfw3.a)
# 编译成可执行文件
add_executable(${PROJECT_NAME} src/main.cpp src/glad.c)
# 需要链接的库
target_link_libraries(${PROJECT_NAME} glfw GL m Xrandr Xi X11 pthread dl Xcursor)
|
显示窗口
CMakeLists.txt
编写好之后,我们就来编写程序实现显示一个窗口
初始化GLFW
在显示窗口之前,还需要先初始化 GLFW
这些都是固定的代码,如下所示
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
int main(int argc, char *argv[])
{
// 初始化 glfw,并设置 版本为3.3,使用核心模式
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
return 0;
}
|
初始好了 GLFW
之后就可以创建窗口了
1
2
3
4
5
6
7
|
GLFWwindow* window = glfwCreateWindow(800, 600, "Window", NULL, NULL);
if (window == NULL) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
|
我们使用 glfwCreateWindow
来创建一个窗口,并且指定窗口的大小为 800*600,窗口的标题为 Window
。
创建完窗口我把窗口的上下文设置为当前的上下文(Context)
这时候如果运行会看到不窗口,因为执行完之后,程序马上就退出了。
初始化 GLAD
在使用 OpenGL
函数之前我们需要使用 GLAD
来帮我们管理 OpenGL
的函数指针,如下所示
1
2
3
4
|
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
|
展示窗口
为了不让程序马上退出,我们需要在一个循环中来处理程序是否需要退出
1
2
3
4
|
while(!glfwWindowShouldClose(window)) {
// 获取键盘和鼠标事件,这里用于检测是否点击了关闭按钮
glfwPollEvents();
}
|
接着运行程序,窗口就显示出来了,但是你会发现窗口是透明的,这是因为我们没有在上面绘制任何东西,点击关闭可以关闭。
glfwWindowShouldClose
是用来检测窗口是否需要关闭,如果你点击了关闭这个函数就会返回 true
绘制背景颜色
1
2
3
4
5
6
|
while(!glfwWindowShouldClose(window)) {
glClearColor(0.f, 0.f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
glfwPollEvents();
}
|
在循环中,我们使用 glClearColor
来清空屏幕的颜色,也就相当与给屏幕设置颜色。 glClearColor
使用的是 rgba
表示法。所以上面程序运行会看到一个蓝色的窗口。

glClear
用来清除颜色缓冲,参数可以是 GL_COLOR_BUFFER_BIT
、 GL_DEPTH_BUFFER_BIT
、 GL_STENCIL_BUFFER_BIT
在这个程序中只使用到了颜色,所以用 GL_COLOR_BUFFER_BIT
就可以了。
调用 glClear
后,就会使用 glClearColor
中设置的颜色了。
接下来是调用 glfwSwapBuffers
函数交换颜色缓冲,在 OpenGL
中使用的是双缓冲(Double Buffer),这么做是由于单缓冲会导致图像闪烁问题。图像绘制需要一定的时间,所以所有的渲染都是在后缓冲上进行,渲染完成后交换两个缓冲,这样图像显示出来就会比较自然。不然看到的可能是前一帧的部分和后一帧的部分。
总结
今天第一次学 OpenGL
就先到这,我们来总结一下套路
- 首先要先编译好
GLFW
,用来创建窗口,处理上下文,接收一些输入事件(鼠标,键盘等等)
- 下载
GLAD
用来管理 OpenGL
的函数指针,便于我们使用 OpenGL
提供的 API
- 在代码中初始化
GLFW
、 GLAD
- 使用
GLFW
创建窗口,绑定上下文
- 使用
OpenGL
提供的函数进行绘制,处理用户的输入
完整代码
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
26
27
28
29
30
31
32
33
34
|
#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
int main(int argc, char *argv[]){
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(800, 600, "Window", NULL, NULL);
if (window == NULL) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
while(!glfwWindowShouldClose(window)) {
glClearColor(0.f, 0.f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
|
参考
你好,窗口 - LearnOpenGL CN