LearnOpenGL,参考https://learnopengl-cn.github.io,从开始到放弃,至于何时放弃,要看心情。
之前也尝试着学习OpenGL的内容,但是不晓得为啥,明明教程都是汉字但是就算是画三角形发现也完全看不懂,果然人笨就是没有办法,后来工作太忙,告辞。
如今工作了一段时间,看来现在是有点飘了,想多花点时间安排自己学习点新鲜玩意儿,企图研究一下这OpenGL到底咋玩的,还是以文字大白话做点记录,免得看了后面忘了前面。
回顾以前的学习误区,最近我问了自己之前OpenGL在我自己学习时的困难在哪?我总结了这几条
1.被一上来复杂的windows窗口程序带跑偏了,忘了自己是要学OpenGL的
2.对LearnOpenGL的很多中文关键描述存在极大的误解,完全没有理解状态机是干嘛的
3.由于存在第二点,于是更加没能用自己的理解自己去组织一边代码,即使是复制粘贴
4.天天在加班
首先要明确一点,我目前要编写的程序是干嘛?在windows窗口里用代码画个图,嗯,没毛病。重点是画图,所以尽可能的暂时忽略窗口程序的细节,那当然要是用框架了。LearnOpenGL里面介绍使用的是GLFW和GLAD,至于里面的细节内容,以当前在记录的我来说,完全不知道是啥。Fine,我也不关心,根据之前工作的套路,先把框架用起来再说。至于布置环境,懒得写了,我看LearnOpenGL教程上配置步奏还是的蛮傻瓜式的,大不了忘了再看一遍
标配:
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
OK,我要画一个三角形,先跟着官方的从一个空工程开始搞起。
首先我需要一个窗口,假定为600*800的大小,OpenGl是怎么做的?
这里要注意的是让GLFW帮我画窗口而不是我直接去设置一堆windows的API去画窗口,我是对GLFW这个框架交流而不是直接对着windows
另外配置过程中详细的函数参数解释不记录,需要的话自己去翻文档,嗯!
第一步逻辑:初始化GLFW框架并且配置框架
在main函数中:
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 我用的是windows,注释掉的这部分是给MAC用的
第二步逻辑,创建windows窗口对象,这里开始就是让GLFW跟windows自己去玩了,我不用自己去设置一大堆windows的配置去创建windows窗口对象
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
第三步逻辑,初始化GLAD,话说为啥不在开头就把GLAD给初始化呢?咱也不晓得,咱也不敢问,完事了以后再自己整理一下代码看看,嗯,下次一定
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
第四步逻辑,设置视口。
这里怎么理解,视口和之前提到的窗口,LearnOpenGL的描述是这样的“在我们开始渲染之前还有一件重要的事情要做,我们必须告诉OpenGL渲染窗口的尺寸大小,即视口(Viewport),这样OpenGL才只能知道怎样根据窗口大小显示数据和坐标。我们可以通过调用glViewport函数来设置窗口的维度(Dimension)”,所以大概是说真正绘制展示出来的部分其实是在视口里做的?
设置视口用的是这个glViewport(0, 0, 800, 600);和窗口保持一致
并且还有一点要注意,在我们操作窗口拖拽改变窗口大小的同时,OpenGL绘制的视口也需要同步改变,所以这里需要使用回调函数,把视口交给windows与窗口变化捆在一起。多说一句,那么回调函数又是个啥?
看一下教程代码是怎么做的,我理解这一块其实也是配置
做了这么一个事情,glfwSetFramebufferSizeCallback设置了,当windows窗口发生变化时,windows同时会拉起运行glViewport这个函数从而保证,OpenGL的视口和windows的窗口大小保持一致,可见glViewport视口的设置并不是我们用代码固定写死自己主动去调用的,而是交给了windows决定width和height每次应该是多少,这部分就是这个回调函数的作用。当然回调函数是函数和函数之间的交流,在这里我们就是用这个跟windows交流的,别忘了自己多研究一下C++代码自己实现一个看看效果,以后肯定还有很多地方会用到的。
第五步逻辑,进入循环
这个也很好理解,毕竟我们的目的是要持续看到这个窗口的,那么就是循环做的。当然这里依然是让GLFW帮我们去做这件事,不是我们自己去写windows的那一套消息循环逻辑,跳出循环则认为这段程序终结,所以在最后glfwTerminate();释放所有资源
while (!glfwWindowShouldClose(window))
{
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
OK,一个简单的黑色的窗口就这样利用GLFW和glad画出来了,按照上述的描述,大概的代码写下来是这样的
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
while (!glfwWindowShouldClose(window))
{
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
当然其实全部都是复制粘贴来的,一切的开始都是基于理解后的粘贴,复制粘贴没有问题,本身大多数内容都是框架部分在设置参数,每一个片段每一个函数的意义要弄明白,流程步骤还是需要记忆的,但是不要过分钻研细枝末节以免忘记了最初的目的
接下来要看看,如何在这个黑色的框框里面,跟着LearnOpenGL教程画点东西,添加点自己的小想法
参考资料:LearnOpenGL--你好,窗口
https://learnopengl-cn.github.io/01%20Getting%20started/03%20Hello%20Window/