这篇是【OpenGL实战一】文章结尾代码的具体详解,也是进入OpenGL编程的第一步!!
在上一节,我们使用glfw和glad创建一个基于VS2015的OpenGL开发环境(Windows)。
在测试代码中,我们并没有搞清楚,这些代码是干什么的。
这一节,我们来仔细分析,并讲解上一节中提到的代码。
思考:想调用OpenGL应该怎么做呢?很简单,请继续往下看
因为我们用到了GLFW和GLAD所以,所以我们需要包含引用它。(没有的请返回看上一节)
#include "glad\glad.h" #include "glfw3.h"
【第一步】初始化GLFW和版本指定。
int main() { //初始化GLFW glfwInit(); //定义OPEN的版本为3.3 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); //主版本 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); //次版本 //使用核心模式 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); }
在main函数中,我们调用glfwInit来初始化glfw库。openGL发展到今天已经有非常多的版本。
我们需要在代码中定义我们想用的opengl版本为3.3,采用核心模式Core。这样就完成了。
其实你可以想像,把OpenGL的绘图环境比喻成一块黑板,我们可以在上面画任何内容。
那么,如何创建一块黑板?因为是基于Windows的,哪这块黑板也应该基于Win窗口。
【第二步】创建Window渲染窗口。
用glfw库创建一个windows窗口也非常的简单,指定宽,高,和窗口标题然后make就出来了。
//创建一个Win窗口 GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL_01", NULL, NULL); if (window==NULL) { printf("无法创建 GLFW 窗口 !"); glfwTerminate();//释放 return -1; } glfwMakeContextCurrent(window);
现在Win窗口有了,那么黑板呢?现在我们继续创建一块“黑板”指定这块黑板有多大。
用到的函数就是glViewport(0, 0, width, height);
但是,窗口万一调整了大小,咱们这块黑板,也应该跟着调整,所以我们定义一个调整尺寸的方法
//渲染尺寸调整 void framebuffer_size_callback(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); }把这个方法注册关联到window上,每当窗口尺寸发生变化时,都调用一下重设渲染尺寸,像这样
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
关于这块黑板,咱们不能直接用它,因为在opengl中规格很多,我们需要交给glad来统一管理。
这时候,glad出场了,初始化一下就可以了
//加载GLAD if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { printf("初始化GLAD失败 !"); return -1; }
* 小技巧,每次启动时窗口的位置都不固定,对于强迫症来说设置窗口居中是最好的选择:
//设置窗口居中 int* winWidth=new int; int* winHeight= new int; glfwGetWindowSize(window, winWidth, winHeight); GLFWmonitor* monitor = glfwGetPrimaryMonitor(); const GLFWvidmode* mode = glfwGetVideoMode(monitor); glfwSetWindowPos(window, (mode->width - *winWidth) / 2, (mode->height - *winHeight) / 2);
【第三步】永不停止的循环。
为什么需要循环?想像我们在黑板上画一个小人,只代表了一帧的图像,并不会动起来。
我们是想要和放电影一样的效果,这就需要将很多帧不停的画出来,在人眼里表现出连续运动的画面。
所以我们定义一个while循环,这个循环一直坚持到等到glfw发出的退出close指令为止。像这样
// 渲染循环 while (!glfwWindowShouldClose(window)) { }
【第四步】接受键盘指令和缓冲交换
我们在第三步提到,while循环会一直等到close指令的发出就会退出。
这个指令,可以由很多情况触发,最常见的就是我们按键盘的ESC键,然后退出程序。
接下来,我们在window上绑定ESC,侦听键盘的输入,如果是按下了ESC,咱们就让它退出。
//按下ESC键退出 void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); }
因为这个侦听是持续的,所以我们把它放在while循环中进行调用。processInput(window);
下面科普一下小知识,什么是双缓冲?
双缓冲(Double Buffer)
应用程序使用单缓冲绘图时可能会存在图像闪烁的问题。 这是因为生成的图像不是一下子被绘制出来的,而是按照从左到右,由上而下逐像素地绘制而成的。最终图像不是在瞬间显示给用户,而是通过一步一步生成的,这会导致渲染的结果很不真实。为了规避这些问题,我们应用双缓冲渲染窗口应用程序。前缓冲保存着最终输出的图像,它会在屏幕上显示;而所有的的渲染指令都会在后缓冲上绘制。当所有的渲染指令执行完毕后,我们交换(Swap)前缓冲和后缓冲,这样图像就立即呈显出来,之前提到的不真实感就消除了。
可以发现,如果不使用双缓冲,咱们画到窗口的东西,会产生闪烁的情况。
所以,接下来要调用一下API来交换缓冲区。glfwSwapBuffers(window);
最后,见证奇迹的时候到了!!
该搞的都准备好了。黑板有了,到底要怎么画??别急,在画之前,首先你要学会" 擦黑板 "。
OpenGL中就有“擦黑板”的方法。glClear
而且,除了擦掉黑板里的东西,还可以指定默认把黑板填充成什么底色。glClearColor
接下来,我们用深蓝绿色来填充这块黑板。代码如下:
// 渲染指令 glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT);
在VS2015中,按调试运行。
好了,这节运行的效果和第一节虽然是一模一样的。但是我相信你已经明白了其中的原理了。
完整C++代码如下,我已经用中文注释好了:
#include "glad\glad.h" #include "glfw3.h" #include <iostream> void framebuffer_size_callback(GLFWwindow* window, int width, int height); void processInput(GLFWwindow *window); int main() { //初始化GLFW glfwInit(); //定义OPEN的版本为3.3 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); //主版本 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); //次版本 //使用核心模式 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //创建一个Win窗口 GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL_01", NULL, NULL); if (window==NULL) { printf("无法创建 GLFW 窗口 !"); glfwTerminate();//释放 return -1; } glfwMakeContextCurrent(window); //每当窗口尺寸发生变化时,重设渲染尺寸 glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); //加载GLAD if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { printf("初始化GLAD失败 !"); return -1; } // 渲染循环 while (!glfwWindowShouldClose(window)) { // 输入 processInput(window); // 渲染指令 glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); // 检查并调用事件 glfwPollEvents(); // 交换缓冲 glfwSwapBuffers(window); } //释放 glfwTerminate(); return 0; } //渲染尺寸调整 void framebuffer_size_callback(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); } //按下ESC键退出 void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); }
既然画板都有了,是不是应该在上面画点像样的东西了呢??
你说的对,接下的文章,就将和你一起用OpenGL学画画。
敬请关注吧~