openGL 第三篇:创建窗口

305 阅读4分钟

​本文已参与「新人创作礼」活动,一起开启掘金创作之路。

知识点的复习与新知识点学习:

1,glfw : 是一个专门针对OpenGL的C语言库,也是一个应用框架,可以使用glfw创建OpenGL的上下文,定义窗口数据,接受输入与事件等操作

2,glad:是一个管理函数指针的开源库。

   a)由于OpenGL驱动版本众多,它大多数函数的位置都无法在编译时确定下来,需要在运行时查询。所以任务就落在了开发者身上,开发者需要在运行时获取函数地址并将其保存在一个函数指针中供以后使用。
   b)取得地址的方法因平台而异,代码非常复杂,而且很繁琐,我们需要对每个可能使用的函数都要重复这个过程。幸运的是,有些库能简化此过程,其中GLAD是目前最新,也是最流行的库。
   c)GLAD是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前我们需要初始化GLAD。GLA也可以使OpenGL基础渲染变得简单。因此在使用函数之前,都需要对glad 进行初始化!

3,向前兼容,向后兼容

    a)向前兼容(forward): 对于未来的版本兼容
    b)向后兼容(backward):兼容过去的版本
    

4,双缓冲(Double Buffer)

    Q:应用程序使用单缓冲绘图时可能会存在图像闪烁的问题。 
    A1,这是因为生成的图像不是一下子被绘制出来的,而是按照从左到右,由上而下逐像素地绘制而成的。最终图像不是在瞬间显示给用户,而是通过一步一步生成的,这会导致渲染的结果很不真实。为了规避这些问题,我们应用双缓冲渲染窗口应用程序。
        2,前缓冲保存着最终输出的图像,它会在屏幕上显示;而所有的的渲染指令都会在后缓冲上绘制。
        3,当所有的渲染指令执行完毕后,我们交换(Swap)前缓冲和后缓冲,这样图像就立即呈显出来,之前提到的不真实感就消除了。

注: OpenGL只是一个标准/规范

代码实践:

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);


int main()
{
    //初始化 glfw
    glfwInit();
    //设置最大版本
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    //设置最小版本
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    //设置渲染模式   core  核心渲染 >= 3.2
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
    //向前兼容
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
    //创建一个窗口  大小为    宽:800    高:600
    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);
    
    //检查 glad 是否加载成功  因glad 是管理函数的指针,在使用函数钱需要提前加载
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }
    //注册窗口大小变动函数  第一次启动时也会调用改函数
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    
    //通过检测 窗口是否关闭   进行循环渲染   窗口是需要不断进行渲染 才能一直显示
    while(!glfwWindowShouldClose(window))
    {
        //设置清空后填充的颜色
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        //清空颜色
        glClear(GL_COLOR_BUFFER_BIT);

        
        //监听输入事件
        processInput(window);
        
        //交互缓冲  因使用的是双缓冲
        /**
         双缓冲(Double Buffer)
         应用程序使用单缓冲绘图时可能会存在图像闪烁的问题。 
         这是因为生成的图像不是一下子被绘制出来的,而是按照从左到右,
         由上而下逐像素地绘制而成的。最终图像不是在瞬间显示给用户,而是通过一步一步生成的,
         这会导致渲染的结果很不真实。为了规避这些问题,我们应用双缓冲渲染窗口应用程序。
         前缓冲保存着最终输出的图像,它会在屏幕上显示;而所有的的渲染指令都会在后缓冲上绘制。
         当所有的渲染指令执行完毕后,我们交换(Swap)前缓冲和后缓冲,这样图像就立即呈显出来,
         之前提到的不真实感就消除了。
         */
        glfwSwapBuffers(window);
        //检查窗口是否触发什么事件,比如:窗口大小发生改变,会调用对应的函数
        glfwPollEvents();
    }
    
    //关闭窗口
    glfwTerminate();
    
    return 0;
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    //窗口左下角坐标,宽度  高度
    glViewport(0, 0, width, height);
}
//输入回调事件
void processInput(GLFWwindow *window)
{
    /**
     检查输入按键
     https://www.glfw.org/docs/latest/group__keys.html#gaac6596c350b635c245113b81c2123b93
     */
    if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}