以下内容整理自:https://learnopengl-cn.github.io/01%20Getting%20started/03%20Hello%20Window/
一.初始化 glfw 并设置相关参数:
1 glfwInit();//使用glfw前必须用glgwInit函数来初始化glfw 2 //用glfwWindowHint函数来配置glfw 3 //我们需要告诉GLFW我们要使用的OpenGL版本是3.3 4 //将主版本号(Major)和次版本号(Minor)都设为3 5 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//选择主版本号 6 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//选择次版本号 7 //我们同样明确告诉GLFW我们使用的是核心模式(Core - profile) 8 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 9 //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 10 //如果使用的是Mac OS X系统则需要将注释的这句加上才能使这些设置生效
二.通过 glfwCreateWindow 函数创建窗口:
1 //接下来我们创建一个窗口对象,这个窗口对象存放了所有和窗口相关的数据, 2 //而且会被GLFW的其他函数频繁地用到 3 GLFWwindow *window = glfwCreateWindow(800, 600, "LearnOpengl", NULL, NULL); 4 //创建窗口,前两个参数为窗口的宽和搞,第三个参数表示窗口的标题,后两个参数暂时不讨论 5 if (window == NULL) { 6 std::cout << "failed to create glfw window" << std::endl; 7 glfwTerminate();//释放之前分配的资源 8 return -1; 9 } 10 //创建完窗口通知GLFW将窗口的上下文设置为当前线程的主上下文 11 glfwMakeContextCurrent(window);
三.初始化 glad:
1 //GLAD是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前 2 //我们需要初始化GLAD 3 //我们给GLAD传入了用来加载系统相关的OpenGL函数指针地址的函数。GLFW给 4 //我们的是glfwGetProcAddress,它根据我们编译的系统定义了正确的函数 5 if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { 6 std::cout << "failed to initialize glad" << std::endl; 7 return -1; 8 }
四.创建视口:
1 //视口 2 //在我们开始渲染之前还有一件重要的事情要做,我们必须告诉OpenGL渲染窗口的尺寸大小, 3 //即视口(Viewport),这样OpenGL才只能知道怎样根据窗口大小显示数据和坐标。 4 //我们可以通过调用glViewport函数来设置窗口的维度 5 glViewport(0, 0, 800, 600);//前两个参数控制左下角的位置,后两个参数控制渲染窗口的宽度和高度(像素) 6 //注意和前面的GLFWwindow区别开来,GLFWwindow定义的是GLFW的维度 7 //我们实际上也可以将视口的维度设置为比GLFW的维度小,这样子之后所有的OpenGL渲染将会在一个更小 8 //的窗口中显示,这样子的话我们也可以将一些其它元素显示在OpenGL视口之外
注意区分创建 glfw 窗口和视口的区别
五.接下来在渲染循环之前我们可以注册我们需要的回掉函数:
1 //我们还需要注册回掉函数,告诉GLFW我们希望每当窗口调整大小的时候调用这个函数 2 glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); 3 //当窗口被第一次显示的时候framebuffer_size_callback也会被调用。对于视网膜(Retina)显示屏,width和height都会明显比原输入值更高一点 4 //我们还可以将我们的函数注册到其它很多的回调函数中。比如说,我们可以创建一个回调函数来处理手柄输入变化,处理错误消息等。我们会在创建窗口之后, 5 //渲染循环初始化之前注册这些回调函数
六.渲染循环:
1 //渲染循环,让glfw退出前一直保持运动 2 //glfwWindowShouldClose函数在我们每次循环的开始前检查一次GLFW是否被要求退出,如果是的话该函数返回true然后渲染循环便结束了,之后为我们就可以关闭应用程序了 3 while (!glfwWindowShouldClose(window)) { 4 processInput(window); 5 6 //清除颜色缓冲之后,整个颜色缓冲都会被填充为glClearColor里所设置的颜色 7 glClearColor(1.0f, 0.0f, 0.0f, 1.0f); 8 //glClear函数清空屏幕的颜色缓冲 9 glClear(GL_COLOR_BUFFER_BIT); 10 11 //glfwSwapBuffers函数会交换颜色缓冲(它是一个储存着GLFW窗口每一个像素颜色值的大缓冲), 12 //它在这一迭代中被用来绘制,并且将会作为输出显示在屏幕上。否则只会显示一片空白 13 glfwSwapBuffers(window); 14 //glfwPollEvents函数检查有没有触发什么事件(比如键盘输入、鼠标移动等)、更新窗口状态,并调用对应的回调函数(可以通过回调方法手动设置) 15 glfwPollEvents(); 16 }
渲染循环的模板:
1 // 渲染循环 2 while(!glfwWindowShouldClose(window)) 3 { 4 // 输入 5 processInput(window); 6 7 // 渲染指令 8 ... 9 10 // 检查并调用事件,交换缓冲 11 glfwPollEvents(); 12 glfwSwapBuffers(window); 13 }
七.释放资源:
1 //当渲染循环结束后我们需要正确释放/删除之前的分配的所有资源 2 glfwTerminate();
完整代码:
1 // hello_window.cpp: 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include <glad/glad.h> 6 #include <GLFW/glfw3.h> 7 #include <iostream> 8 9 10 //当用户改变窗口的大小的时候,视口也应该被调整。我们可以对窗口注册一个回调函数(Callback Function), 11 //它会在每次窗口大小被调整的时候被调用 12 void framebuffer_size_callback(GLFWwindow *window, int width, int heigh) { 13 glViewport(0, 0, width, heigh); 14 } 15 16 //使用GLFW的glfwGetKey函数,它需要一个窗口以及一个按键作为输入。这个函数将会返回这个按键是否正在被按下 17 void processInput(GLFWwindow *window) { 18 //这里我们检查用户是否按下了返回键(Esc)(如果没有按下,glfwGetKey将会返回GLFW_RELEASE。 19 //如果用户的确按下了返回键,我们将通过glfwSetwindowShouldClose使用把WindowShouldClose属性设置为 true的方法关闭GLFW 20 if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { 21 glfwSetWindowShouldClose(window, true); 22 } 23 } 24 25 int main() 26 { 27 glfwInit();//使用glfw前必须用glgwInit函数来初始化glfw 28 //用glfwWindowHint函数来配置glfw 29 //我们需要告诉GLFW我们要使用的OpenGL版本是3.3 30 //将主版本号(Major)和次版本号(Minor)都设为3 31 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//选择主版本号 32 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//选择次版本号 33 //我们同样明确告诉GLFW我们使用的是核心模式(Core - profile) 34 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 35 //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 36 //如果使用的是Mac OS X系统则需要将注释的这句加上才能使这些设置生效 37 38 //接下来我们创建一个窗口对象,这个窗口对象存放了所有和窗口相关的数据, 39 //而且会被GLFW的其他函数频繁地用到 40 GLFWwindow *window = glfwCreateWindow(800, 600, "LearnOpengl", NULL, NULL); 41 //创建窗口,前两个参数为窗口的宽和搞,第三个参数表示窗口的标题,后两个参数暂时不讨论 42 if (window == NULL) { 43 std::cout << "failed to create glfw window" << std::endl; 44 glfwTerminate();//释放之前分配的资源 45 return -1; 46 } 47 //创建完窗口通知GLFW将窗口的上下文设置为当前线程的主上下文 48 glfwMakeContextCurrent(window); 49 50 //GLAD是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前 51 //我们需要初始化GLAD 52 //我们给GLAD传入了用来加载系统相关的OpenGL函数指针地址的函数。GLFW给 53 //我们的是glfwGetProcAddress,它根据我们编译的系统定义了正确的函数 54 if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { 55 std::cout << "failed to initialize glad" << std::endl; 56 return -1; 57 } 58 59 //视口 60 //在我们开始渲染之前还有一件重要的事情要做,我们必须告诉OpenGL渲染窗口的尺寸大小, 61 //即视口(Viewport),这样OpenGL才只能知道怎样根据窗口大小显示数据和坐标。 62 //我们可以通过调用glViewport函数来设置窗口的维度 63 glViewport(0, 0, 800, 600);//前两个参数控制左下角的位置,后两个参数控制渲染窗口的宽度和高度(像素) 64 //注意和前面的GLFWwindow区别开来,GLFWwindow定义的是GLFW的维度 65 //我们实际上也可以将视口的维度设置为比GLFW的维度小,这样子之后所有的OpenGL渲染将会在一个更小 66 //的窗口中显示,这样子的话我们也可以将一些其它元素显示在OpenGL视口之外 67 68 //我们还需要注册回掉函数,告诉GLFW我们希望每当窗口调整大小的时候调用这个函数 69 glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); 70 //当窗口被第一次显示的时候framebuffer_size_callback也会被调用。对于视网膜(Retina)显示屏,width和height都会明显比原输入值更高一点 71 //我们还可以将我们的函数注册到其它很多的回调函数中。比如说,我们可以创建一个回调函数来处理手柄输入变化,处理错误消息等。我们会在创建窗口之后, 72 //渲染循环初始化之前注册这些回调函数 73 74 //渲染循环,让glfw退出前一直保持运动 75 //glfwWindowShouldClose函数在我们每次循环的开始前检查一次GLFW是否被要求退出,如果是的话该函数返回true然后渲染循环便结束了,之后为我们就可以关闭应用程序了 76 while (!glfwWindowShouldClose(window)) { 77 processInput(window); 78 79 //清除颜色缓冲之后,整个颜色缓冲都会被填充为glClearColor里所设置的颜色 80 glClearColor(1.0f, 0.0f, 0.0f, 1.0f); 81 //glClear函数清空屏幕的颜色缓冲 82 glClear(GL_COLOR_BUFFER_BIT); 83 84 //glfwSwapBuffers函数会交换颜色缓冲(它是一个储存着GLFW窗口每一个像素颜色值的大缓冲), 85 //它在这一迭代中被用来绘制,并且将会作为输出显示在屏幕上。否则只会显示一片空白 86 glfwSwapBuffers(window); 87 //glfwPollEvents函数检查有没有触发什么事件(比如键盘输入、鼠标移动等)、更新窗口状态,并调用对应的回调函数(可以通过回调方法手动设置) 88 glfwPollEvents(); 89 } 90 91 //当渲染循环结束后我们需要正确释放/删除之前的分配的所有资源 92 glfwTerminate(); 93 94 return 0; 95 }