配置 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);
}
相關文章
相關標籤/搜索