OpenGL入门——第一个窗口
先初始GLFW窗口
///窗口初始化 glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//主版本号,当API以不兼容的方式更改时,该值会增加。 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//次版本号,当特性被添加到API中时,它会增加,但是它保持向后兼容。 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//使用核心模式,不兼容已废弃函数
然后创建一个窗口化对象
GLFWwindow* window = glfwCreateWindow(800, 600, "ping-window", NULL, NULL); if (window == NULL) { std::cout << "failed to create GLFW window" << std::endl; glfwTerminate();//释放/删除之前的分配的所有资源 return nullptr; }
glfwMakeContextCurrent(window);//将窗口的上下文设置为当前线程的主上下文
因为GLAD是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前都需要初始化GLAD。
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))//给GLAD传入了用来加载系统相关的OpenGL函数指针地址的函数 { std::cout << "failed to intialize GLAD" << std::endl; return nullptr; }
设置视口的大小,处理过的OpenGL坐标范围只为-1到1,因此我们事实上将(-1到1)范围内的坐标映射到(0, 800)和(0, 600)
glViewport(0, 0, 800, 600);
glViewport函数前两个参数控制窗口左下角的位置。第三个和第四个参数控制渲染窗口的宽度和高度(像素)。
当用户改变窗口的大小的时候,视口也应该被调整。我们可以对窗口注册一个回调函数(Callback Function),它会在每次窗口大小被调整的时候被调用:
//改变窗口大小 void framebuffer_size_callback(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); }
还需要注册这个函数,告诉GLFW每当窗口调整大小的时候调用这个函数:
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//注册为调整窗口回调函数
当窗口被第一次显示的时候framebuffer_size_callback也会被调用。
现在可以开始绘制图像啦,程序中我们使用while渲染循环,因为我们不想绘制一次就退出程序,而是在关闭程序前一直绘制,如下
while (!glfwWindowShouldClose(window)) { processInput(window); //render glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glfwSwapBuffers(window);//交换颜色缓冲(它是一个储存着GLFW窗口每一个像素颜色值的大缓冲) glfwPollEvents();//检查有没有触发什么事件 }
- glfwWindowShouldClose函数在我们每次循环的开始前检查一次GLFW是否被要求退出。
- glClearColor来设置清空屏幕所用的颜色
- glClear函数清空屏幕的颜色缓冲,它接受一个缓冲位(Buffer Bit)来指定要清空的缓冲,可能的缓冲位有GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT。这里只关心颜色值,所以只清空颜色缓冲。
- glfwPollEvents函数检查有没有触发什么事件(比如键盘输入、鼠标移动等)、更新窗口状态,并调用对应的回调函数。
- glfwSwapBuffers函数会交换颜色缓冲,它在这一迭代中被用来绘制,并且将会作为输出显示在屏幕上。
- processInput窗口输入控制,用来实现一些输入控制
void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)//点击ESC键退出绘制 glfwSetWindowShouldClose(window, true); }
最后退出绘制窗口时,要记得使用glfwTerminate函数释放资源
glfwTerminate();//释放/删除之前的分配的所有资源
好了,可以开始运行程序了,显示效果如图
所有代码
//GLAD的头文件包含了正确的OpenGL头文件(例如GL/gl.h),所以需要在其它依赖于OpenGL的头文件之前包含GLAD #include <glad/glad.h> #include <GLFW/glfw3.h> #include <iostream> //改变窗口大小 void framebuffer_size_callback(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); } //输入 void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)//点击ESC键退出绘制 glfwSetWindowShouldClose(window, true); } GLFWwindow* init_window() { ///窗口初始化 glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//主版本号,当API以不兼容的方式更改时,该值会增加。 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//次版本号,当特性被添加到API中时,它会增加,但是它保持向后兼容。 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//使用核心模式,不兼容已废弃函数 //创建glfw窗口 GLFWwindow* window = glfwCreateWindow(800, 600, "ping-window", NULL, NULL); if (window == NULL) { std::cout << "failed to create GLFW window" << std::endl; glfwTerminate();//释放/删除之前的分配的所有资源 return nullptr; } glfwMakeContextCurrent(window);//将窗口的上下文设置为当前线程的主上下文 glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//注册为调整窗口回调函数 //GLAD是用来管理OpenGL的函数指针的,在调用任何OpenGL的函数之前初始化GLAD if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))//给GLAD传入了用来加载系统相关的OpenGL函数指针地址的函数 { std::cout << "failed to intialize GLAD" << std::endl; return nullptr; } glViewport(0, 0, 800, 600);//处理过的OpenGL坐标范围只为-1到1,因此我们事实上将(-1到1)范围内的坐标映射到(0, 800)和(0, 600) return window; } int hello_window() { GLFWwindow* window = init_window(); while (!glfwWindowShouldClose(window)) { processInput(window); //render glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glfwSwapBuffers(window);//交换颜色缓冲(它是一个储存着GLFW窗口每一个像素颜色值的大缓冲) glfwPollEvents();//检查有没有触发什么事件 } std::cout << "finish!" << std::endl; glfwTerminate();//释放/删除之前的分配的所有资源 return 0; } int main() { hello_window(); return 0; }