【笔记】跟着LearnOpenGL自说自话地学习OpenGL(一)

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/