《Learn OpenGL》 Ch 01 Hello Window
本部分的实现代码,见 01_CreateWindow
在 Ch 00 Creating a Window 的最后,我们通过一系列代码绘制出了一个纯色的面板,但并没有解释相关的代码。在这一章中,我们将从 0 逐步解释这些代码。
#引入相关库
1 |
#初始化GLFW
在 main
函数的最开始,初始化 GLFW
库,后续将使用 GLFW
来创建窗口。
1 | glfwInit(); |
glfwWindowHint
函数的第一个参数用来表示要设定的参数,所有参数都是以GLFW_
开头,函数的第二个参数是需要设定的值。 glfwWindowHint
接受的参数与参数值,可以在GLFW文档中设置。
#创建GLFW窗口
1 | GLFWwindow *window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); |
通过glfwCreateWindow
函数创建窗口,前两个参数设置窗口的宽和高,第三个参数设置窗口名,最后两个参数教程中未做解释。该函数会返回一个GLFWWINDOW
类型的指针。
glfwMakeContextCurrent
将glfwCreateWindow
返回的表示窗口的指针绑定给当前线程环境。
#初始化GLAD
1 | if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) |
GLAD
用来管理OpenGL函数的地址,因此在调用任何的OpenGL函数前需要先对GLAD
进行初始化。
需要给gladLoadGLLoader
指定读取函数地址的函数,函数地址是系统相关的。在绑定了窗口后,可以通过glfwGetProcAddress
函数获取到相应系统给出的函数地址。
因此需要先初始化GLFW
,绑定GLFW
窗口,再初始化GLAD
,然后才能使用OpenGL相应的函数。
#渲染循环
此时在主函数中,就可以设置渲染循环,在其中只要 glfwWindowShouldClose
不返回 true
,就意味着窗口不应该被关闭。当窗口不关闭时,就需要进行一系列的渲染操作。
1 | while (!glfwWindowShouldClose(window)) |
glClearColor
设置ClearColor
的颜色。
glClear
设置需要清理的对象,这里仅清理颜色缓存。
glfwSwapBuffers
设置双缓冲。如果仅使用单缓存时可能会有图像闪烁的原因,因为图像并不是瞬间被画出,而是从左至右,从下至上逐像素画出。为避免这种情况的发生,可以用双缓存,当前缓存在显示时,后缓存进行读取,当后缓存读完,交换前后缓存,如此,图像可瞬间画出。
glfwPollEvents
用来检查是否有事件触发,包括键盘事件,鼠标事件,和窗口事件等。(即使不需要处理输入,也仍然要设定该函数)。
#按键处理
设置函数 processInput
处理按键信息:
1 | void processInput(GLFWwindow *window) |
glfwGetKey
用来获取当前窗口按下的按键。 glfwSetWindowShouldClose
设置当前窗口需要被关闭,调用该函数后,窗口会被关闭。
processInput
函数需要在函数主循环中被调用,保证一直检查输入状态。
在渲染循环 的最开始调用 processInput
函数,保证在渲染前处理的按键信息:
1 | while (!glfwWindowShouldClose(window)) { |
#Viewport设置
当缩放窗口时,需要重新调用 glViewport
以保证渲染的范围与窗口的大小匹配。
为做到这一点,我们定义函数 framebuffer_size_callback
作为窗口大小改变时的回调函数,在回调中通过 glViewport
函数设置视口:
1 | void framebuffer_size_callback(GLFWwindow *window, int width, int height) |
通过 glfwSetFramebufferSizeCallback
将函数 framebuffer_size_callback
设置为窗口大小改变时的回调函数。因为注册回调只需要一次,因此将其放在渲染循环前:
1 | glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); |
#终止GLFW
在主函数的最后,调用 glfwTerminate
关闭窗口:
1 | int main() |