配置 OpenGL(Win10 + VS2019 + GLAD + GLFW) 并建立本身的第一个 OpenGL 项目

在画出出色的效果以前,首先要作的就是建立一个 OpenGL 上下文和一个用于显式的窗口。
一些函数库已经提供了这样的功能,能够提供给开发者一个窗口和上下文来渲染。
比较流行的有 GLUT, SDL, SFML, GLFW, 此处咱们使用 GLFW.html

OpenGL 相关库

OpenGL 相关库简介

  • GLEW 是对底层 OpenGL 的接口的封装,可让开发者的代码跨平台
  • GLAD 与 GLEW 做用基本相同,能够看做是它的升级版本
  • Freeglut 主要用于建立 OpenGL 上下文、接受一些鼠标键盘事件等等
  • GLFW 做用与 Freeglut 基本相同,能够看做是它的升级版

GLAD 一般和 GLFW 配合使用; GLEW 一般和 Freeglut 配合使用。c++

GLFW

  • 简介
    GLFW 是一个专门针对 OpenGL 的 C 语言库,它提供了一些渲染物体所须要的最低限度的接口。它容许用户建立 OpenGL 上下文,定义窗口参数以及处理用户输入。git

  • 官网下载
    GLFW 须要从 GLFW 官网进行下载。
    github

    能够下载源文件而后配合 CMake 工具生成对应的二进制版本和头文件,具体的作法可参见连接:LearnOpenGL CN
    也能够直接下载了官网编译好的二进制版本,建议下载 32 位版本。缓存

  • 百度云下载
    https://pan.baidu.com/s/1CCtc0sy1WpkScIkP3GZD8A 提取码 9hjy函数

GLAD

因为 OpenGL 驱动版本众多,它大多数函数的位置都没法在编译时肯定下来,须要在运行时查询。因此任务就落在了开发者身上,开发者须要在运行时获取函数地址并将其保存在一个函数指针中供之后使用。然而这个过程既复杂有繁琐,而 GLAD 库能够简化此过程。工具

  • 官网下载
    打开 GLAD 的在线服务,选择以下配置后进行生成,选择压缩文件 glad.zip 下载便可。spa

    • 将语言(Language)设置为 C/C++
    • 将OpenGL API 版本(API gl)设置为最新的版本(向下兼容);
    • 将模式(Profile)设置为 Core;
    • 勾选生成加载器(Generate a loader)选项。

  • 百度云下载
    https://pan.baidu.com/s/1LlBCLbRNDSUNUKz4kzw_ow 提取码 54xk线程

配置 GLAD & GLAF

将获得的压缩包进行解压。
为了方即可以将使用须要的文件放在指定的目录中。此处我选择将其放在文件夹 C:\Program Files\OpenGL 中。指针

  • 将解压后的 GLFW 文件夹中的 includelib-vc2019 (若是是其它版本的 VS 记得改成其它版本)复制到文件夹 C:\Program Files\OpenGL 中;
  • 将解压后的 GLAD 文件夹中的 include 文件夹中的 gladKHR 文件夹复制到文件夹 C:\Program Files\OpenGL\include 中;
  • 将解压后的 GLAD 文件夹中的 src 文件夹复制到文件夹 C:\Program Files\OpenGL 中;

移动后的文件结构以下:

OpenGL include glad
GLFW
KHR
vc2019 ...
src glad.c

建立工程及配置

  • 打开 VS2019 新建一个空白工程;
  • 右键解决方案名称选择属性
  • 点击VC++项目中的包含目录,添加 OpenGL 的 include 目录,此处为 C:\Program Files\OpenGL\include ;
  • 点击VC++项目中的库文件,添加 OpenGL 的工程库目录,此处为 C:\Program Files\OpenGL\lib-vc2019 ;
  • 点击连接器中的输入中的附加依赖项,添加库文件 glfw.lib ;
  • 在新项目中添加 C:\Program Files\OpenGL\src 文件夹下的源文件 glad.c(每次新建工程都要添加);

新建窗口

  • 新建一个源文件,要包含如下头文件

    #include <glad/glad.h>
    #include <GLFW/glfw3.h>
  • 建立 main 函数,实例化 GLFW 窗口

    int main() {
        // 初始化 GLFW
        glfwInit();
        // 配置 GLFW
        // 第一个参数是 enum 类型表示选项名称
        // 第二个参数是 int 类型用于设置第一个参数的值
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);                  // 设置主版本号
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);                  // 设置次版本号
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  // 使用核心模式
        // 仅 Mac OS X 系统须要下面的语句
        //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    
        return 0;
    }
  • 建立一个窗口对象

    // glfwCreateWindow 函数用于建立窗口对象 glfwCreateWindow
    // 第1、2、三个参数分别是窗口的宽度、高度、窗口的标题
    // 后两个参数暂时先忽略
    // 返回一个 GLFWwindow 对象的指针
    GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
    if (window == NULL) {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    
    // 窗口建立成功以后通知 GLFW 将窗口的上下文设置为当前线程的主上下文 
    glfwMakeContextCurrent(window);
  • 加载系统储相关的 OpenGL 函数指针地址
    GLAD 是用来管理 OpenGL 的函数指针的,因此任何调用 OpenGL 的函数以前都要初始化 GLAD。

    // gladLoadGLLoader: GLAD 装载 GL 装载机
    // glfwGetProcAddress: GLFW 根据编译的系统定义正确的函数
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }
  • 视口
    在开始渲染以前必需要告诉 OpenGL 渲染矩形区域的尺寸大小,即视口(Viewport)。
    视口的大小能够和窗口相同,也能够大于或者小于窗口的大小。
    只有绘制在视口区域的图形才能显式,

    // glViewport: 设置视口的锚点和大小
    // 第1、二个参数控制视口左下角的位置,窗口左下角为(0, 0)
    // 第3、四个参数控制视口的大小(单位:像素)
    glViewport(0, 0, 800, 600);

    当用户改变窗口的大小时,视口也应该被调整。
    能够对窗口注册一个回调函数,它会在每次窗口大小被调整时被调用。

    // 回调函数第一个参数是窗口对象指针
    // 回调函数的后两个参数是窗口被改变以后的宽度和高度
    void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
        glViewport(0, 0, width, height);
    }

    另外,还须要注册这个回调函数,告诉 GLFW 开发者但愿每当窗口调整大小的时候调用这个函数。

    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
  • 渲染循环
    在程序中添加一个 while 循环用于在 GLFW 推出以前不断的绘制图像并接受用户的输入。

    while(!glfwWindowShouldClose(window)) { 
        glfwSwapBuffers(window);
        glfwPollEvents();    
    }
    • glfwWindowShouldClose 函数在每次循环开始时检查一次 GLFW 是否被要求退出。
    • glfwPollEvents 函数检测是否触发了什么事件、更新窗口状态,并调用对应的回调函数。
    • glfwSwapBuffers 函数会交换颜色缓存,它在这一迭代中被用来绘制,而且做为输出显示在屏幕上。

    双缓冲(Double buffer)
    应用程序使用单缓冲绘图时会可出现图像闪烁的问题,这是由于生成的图像不是一会儿被绘制出来的,而是一步步生成的,这致使渲染的结果不真实。
    为了不这一问题,咱们采用双缓冲渲窗口应用程序。其中,前缓冲中保存着最终输出的图像;后换冲用于绘制全部的渲染指令。当全部的渲染指令完成以后,交换先后缓冲,图像就会当即显示出来。

  • 正确释放/删除以前的分配的全部资源

    // 正确释放/删除以前的分配的全部资源
    glfwTerminate();

输入

以获取一个按键输入为例:当按下 Escape 按键时关闭窗口。

// 建立一个 processInput 来处理输入
void processInput(GLFWwindow *window) {
    // glfwGetKey 用于检查按键 Escape 是否被按下(若是按下了返回 GLDFW_RELEASE)
    // glfwSetWindowShouldClose 用于 Escape 按下时将 WindowShouldClose 属性设置为 true
    if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);         // 下一次循环就会关闭 GLFW
}

// 在循环渲染的每次迭代中调用 processInput
while (!glfwWindowShouldClose(window)) {
    processInput(window);

    glfwSwapBuffers(window);
    glfwPollEvents();
}

渲染

咱们要把全部的渲染(Rendering)操做放到渲染循环中,从而保证渲染指令在每次渲染循环迭代的时候都能被执行。

// 渲染循环
while(!glfwWindowShouldClose(window)) {
    // 输入
    processInput(window);

    // 渲染指令
    ...

    // 检查并调用事件,交换缓冲
    glfwPollEvents();
    glfwSwapBuffers(window);
}
相关文章
相关标签/搜索