01 创建一个窗口

本文详细介绍了使用glad和glfw创建OpenGL窗口的全过程,包括初始化GLFW库、设置OpenGL版本、创建窗口、初始化GLAD、设置视口回调、渲染循环及资源清理。关键步骤包括配置OpenGL版本3.3核心模式、窗口回调和双缓冲技术的应用。
摘要由CSDN通过智能技术生成

https://learnopengl-cn.github.io/01%20Getting%20started/03%20Hello%20Window/

https://zhuanlan.zhihu.com/p/107671711

使用:glad+glfw

1 创建窗口的步骤:

  1. 初始化GLFW语言库,之后才可以调用GLFW库里大部分的函数

  2. 配置GLFW,说明要使用的版本与使用的模式;

    1. 教程都是基于OpenGL 3.3版本展开讨论的,所以需要告诉GLFW我们要使用的OpenGL版本是3.3,这样GLFW会在创建OpenGL上下文时做出适当的调整。这也可以确保用户在没有适当的OpenGL版本支持的情况下无法运行。
    2. 同样明确告诉GLFW我们使用的是核心模式(Core-profile)。明确告诉GLFW我们需要使用核心模式意味着我们只能使用OpenGL功能的一个子集(没有我们已不再需要的向后兼容特性)。
  3. 创建窗口,设置窗口的长宽与窗口的名字;

  4. 初始化GLAD

    GLAD是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前我们需要初始化GLAD。

  5. 初始化渲染视口,声明对应的回调函数

    在开始渲染之前必须告诉OpenGL渲染窗口的尺寸大小,即视口(Viewport),这样OpenGL才只能知道怎样根据窗口大小显示数据和坐标;

    你也可以将视口的大小设置为比GLFW窗口小。这样子之后所有的OpenGL渲染将会在一个更小的窗口中显示,这样子的话我们也可以将一些其它元素显示在OpenGL视口之外;

    1. 然而,当用户改变窗口的大小的时候,视口也应该被调整。我们可以对窗口注册一个回调函数(Callback Function),它会在每次窗口大小被调整的时候被调用;
  6. 创建渲染循环

    我们希望程序在我们主动关闭它之前不断绘制图像并能够接受用户输入。因此,我们需要在程序中添加一个while循环,我们可以把它称之为渲染循环(Render Loop),它能在我们让GLFW退出前一直保持运行;

  7. 删除之前分配的资源,释放内存

2 代码示例

注意:请确认是在包含GLFW的头文件之前包含了GLAD的头文件。GLAD的头文件包含了正确的OpenGL头文件(例如GL/gl.h),所以需要在其它依赖于OpenGL的头文件之前包含GLAD。

// 该例子的教程:https://learnopengl-cn.github.io/01%20Getting%20started/03%20Hello%20Window/

//请确认是在包含GLFW的头文件之前包含了GLAD的头文件。GLAD的头文件包含了正确的OpenGL头文件(例如GL/gl.h),所以需要在其它依赖于OpenGL的头文件之前包含GLAD。
#include <glad/glad.h> 
#include <GLFW/glfw3.h>

#include <iostream>

// 当用户改变窗口的大小的时候,视口也应该被调整。对窗口注册一个回调函数(Callback Function),它会在每次窗口大小被调整的时候被调用。
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
	// 5. 初始化渲染视口,声明对应的回调函数
    glViewport(0, 0, width, height); // 左下角、宽度、高度(单位:像素)
}

void processInput(GLFWwindow *window);

// 设置窗口的宽和高
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

int main()
{
    // 1. 初始化GLFW
    glfwInit(); 
    // 2. 配置GLFW,说明要使用的版本与使用的模式
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // 2.1 主版本号
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // 2.2 次版本号
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

#ifdef __APPLE__ //可选:如果使用的是Mac OS X系统,你还需要加下面这行代码到你的初始化代码中这些配置才能起作用(将下面的代码解除注释)
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

    
    // 3. 创建窗口并设置其大小、名称,与检测是否创建成功
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window); // 创建完窗口,需要让当前窗口的环境在当前线程上成为当前环境,就是接下来的画图都会画在我们刚刚创建的窗口上
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); // 注册这个函数,告诉GLFW我们希望每当窗口调整大小的时候调用这个函数
    
    // 4. glad寻找opengl的函数地址,调用opengl的函数前需要初始化glad
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }    

    // 6. 创建渲染循环
    // render loop(不希望只绘制一个图像之后我们的应用程序就立即退出并关闭窗口。我们希望程序在我们主动关闭它之前不断绘制图像并能够接受用户输入。)
    while (!glfwWindowShouldClose(window))
    {
        // input(响应键盘输入)
        // -----
        processInput(window);

        // render(渲染指令)
        // ------
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f); // 当调用glClear函数,清除颜色缓冲之后,整个颜色缓冲都会被填充为glClearColor里所设置的颜色。在这里,我们将屏幕设置为了类似黑板的深蓝绿色。
        glClear(GL_COLOR_BUFFER_BIT);

        // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
        glfwSwapBuffers(window); // 【是一个状态设置函数】glfwSwapBuffers函数会交换颜色缓冲(它是一个储存着GLFW窗口每一个像素颜色值的大缓冲),它在这一迭代中被用来绘制,并且将会作为输出显示在屏幕上。
        glfwPollEvents(); // 【状态使用的函数,它使用了当前的状态来获取应该要清除的颜色】glfwPollEvents函数检查有没有触发什么事件(比如键盘输入、鼠标移动等)、更新窗口状态,并调用对应的回调函数(可以通过回调方法手动设置)。
    }

    // 7. 释放前面所申请的资源
    // (当渲染循环结束后我们需要正确释放/删除之前的分配的所有资源。)
    glfwTerminate();
    
    
    return 0;
}

// 可选:如果希望能够在GLFW中实现一些输入控制,这可以通过使用GLFW的几个输入函数来完成。
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
    if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) // glfwGetKey函数,它需要一个窗口以及一个按键作为输入。这个函数将会返回这个按键是否正在被按下。
                                                          // 这里我们检查用户是否按下了返回键(Esc)如果没有按下,glfwGetKey将会返回GLFW_RELEASE。
        glfwSetWindowShouldClose(window, true);          // 如果用户的确按下了返回键,我们将通过glfwSetwindowShouldClose使用把WindowShouldClose属性设置为 true的方法关闭GLFW,
                                                        // 下一次while循环的条件检测将会失败,程序将会关闭。
}

3 相关函数

3.1 glfwCreateWindow()

GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nullptr, nullptr);
//glfwCreateWindow()接受5个参数。
//第一个、第二个是窗口的宽和高,以像素为单位,这里分别是800和600;
//第三个是窗口标题,这里是"LearnOpenGL";
//第四个和第五个参数可以忽略,直接传入nullptr。

//glfwCreateWindow()将会使用前面glfwWindowHint()所设置的hint创建窗口,返回一个GLFWwindow指针,
//我们把这个指针叫做窗口句柄(window handle)
//简单说来,就是从此以后我们都用它来代表我们的窗口,后面会需要对窗口进行设置、询问一些关于窗口的信息,就需要传入这个指针

3.2 glfwSwapBuffers(window)

//用来交换窗口的两个颜色缓冲(color buffer)。这个概念叫做双缓冲(double buffer)。
//如果不使用双缓冲,就可能会出现闪屏现象,因为绘制一般不是一下子就绘制完毕的,而是从左到右、从上到下地绘制。
//为了避免这个问题,一般会使用双缓冲,前缓冲(front buffer)是最终的图像,而程序会在后缓冲(back buffer)上绘制。
//后缓冲绘制完毕后,就交换两个缓冲,这样就不会有闪屏的问题了。
glfwSwapBuffers(window)

3.3 glfwPollEvents()

//用来检查是否有事件被触发,例如点击关闭按钮、点击鼠标、按下键盘,等等。
// GLFW将会对这些事件进行处理。
//更严谨地说(以键盘、鼠标键为例),GLFW自己会记录每个键、鼠标键的状态(按下 / 没有按下),但当某个按键松开或被按下时,GLFW不会自动更新状态,必须调用glfwPollEvents()才能更新。
//调用glfwPollEvents()时会检查状态是否有变化(如按下的是否松开,没有按下的是否被按下),如果有就会更新该状态。
//如果设置了回调函数,还会调用相应的回调函数。如果不调用这个函数,不仅无法检测输入(后文会需要这样),我们在点击窗口右上角的X时,GLFW也不会知道需要关闭窗口。
//所以必须在每一轮游戏循环中调用这个函数。
glfwPollEvents()

3.4 glClearColor(0.2f, 0.3f, 0.3f, 1.0f)、glClear()

// 与其它glfw开头的函数(这些函数由GLFW提供)不同,这个函数是以gl开头的,是OpenGL的函数。
// glClearColor用来设置窗口被清除时的颜色,也就是背景颜色。前3个参数分别是背景颜色的R、G、B分量,范围是0~1;
// 当调用glClear函数,清除颜色缓冲之后,整个颜色缓冲都会被填充为glClearColor里所设置的颜色。
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear()函数:
    清空屏幕的颜色缓冲,它接受一个缓冲位(Buffer Bit)来指定要清空的缓冲,可能的缓冲位有GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT。
    // 由于现在我们只关心颜色值,所以我们只清空颜色缓冲。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值