1. 程式人生 > >LearnOpenGL~建立視窗

LearnOpenGL~建立視窗

建立視窗

原文 Creating a window
作者 JoeyDeVries
翻譯 gjy_1992, Krasjet
校對 暫未校對

譯註

注意,由於作者對教程做出了更新,之前本節使用的是GLEW庫,但現在改為了使用GLAD庫,關於GLEW配置的部分現在已經被修改,但我仍決定將這部分教程保留起來,放到一個歷史存檔中,如果有需要的話可以到這裡來檢視。

在我們畫出出色的效果之前,首先要做的就是建立一個OpenGL上下文(Context)和一個用於顯示的視窗。然而,這些操作在每個系統上都是不一樣的,OpenGL有目的地從這些操作抽象(Abstract)出去。這意味著我們不得不自己處理建立視窗,定義OpenGL上下文以及處理使用者輸入。

幸運的是,有一些庫已經提供了我們所需的功能,其中一部分是特別針對OpenGL的。這些庫節省了我們書寫作業系統相關程式碼的時間,提供給我們一個視窗和上下文用來渲染。最流行的幾個庫有GLUT,SDL,SFML和GLFW。在教程裡我們將使用GLFW

GLFW

GLFW是一個專門針對OpenGL的C語言庫,它提供了一些渲染物體所需的最低限度的介面。它允許使用者建立OpenGL上下文,定義視窗引數以及處理使用者輸入,這正是我們需要的。

GLFW Logo

本節和下一節的目標是建立GLFW環境,並保證它恰當地建立OpenGL上下文並顯示視窗。這篇教程會一步步從獲取、編譯、連結GLFW庫講起。我們使用的是Microsoft Visual Studio 2015 IDE(操作過程在新版的Visual Studio都是相同的)。如果你用的不是Visual Studio(或者用的是它的舊版本)請不要擔心,大多數IDE上的操作都是類似的。

構建GLFW

GLFW可以從它官方網站的下載頁上獲取。GLFW已經有針對Visual Studio 2013/2015的預編譯的二進位制版本和相應的標頭檔案,但是為了完整性我們將從編譯原始碼開始。所以我們需要下載原始碼包

如果你要使用預編譯的二進位制版本的話,請下載32位的版本而不是64位的(除非你清楚你在做什麼)。大部分讀者反映64位版本會出現很多奇怪的問題。

下載原始碼包之後,將其解壓並開啟。我們只需要裡面的這些內容:

  • 編譯生成的庫
  • include資料夾

從原始碼編譯庫可以保證生成的庫是相容你的作業系統和CPU的,而預編譯的二進位制檔案可能會出現相容問題(甚至有時候沒提供支援你係統的檔案)。提供原始碼所產生的一個問題在於不是每個人都用相同的IDE開發程式,因而提供的工程/解決方案檔案可能和一些人的IDE不相容。所以人們只能從.c/.cpp和.h/.hpp檔案來自己建立工程/解決方案,這是一項枯燥的工作。但因此也誕生了一個叫做CMake的工具。

CMake

CMake是一個工程檔案生成工具。使用者可以使用預定義好的CMake指令碼,根據自己的選擇(像是Visual Studio, Code::Blocks, Eclipse)生成不同IDE的工程檔案。這允許我們從GLFW原始碼裡建立一個Visual Studio 2015工程檔案,之後進行編譯。首先,我們需要從這裡下載安裝CMake。我選擇的是Win32安裝程式。

當CMake安裝成功後,你可以選擇從命令列或者GUI啟動CMake,由於我不想讓事情變得太過複雜,我們選擇用GUI。CMake需要一個原始碼目錄和一個存放編譯結果的目標檔案目錄。原始碼目錄我們選擇GLFW的原始碼的根目錄,然後我們新建一個 build 資料夾,選中作為目標目錄。

在設定完原始碼目錄和目標目錄之後,點選Configure(設定)按鈕,讓CMake讀取設定和原始碼。我們接下來需要選擇工程的生成器,由於我們使用的是Visual Studio 2015,我們選擇 Visual Studio 14 選項(因為Visual Studio 2015的內部版本號是14)。CMake會顯示可選的編譯選項用來配置最終生成的庫。這裡我們使用預設設定,並再次點選Configure(設定)按鈕儲存設定。儲存之後,點選Generate(生成)按鈕,生成的工程檔案會在你的build資料夾中。

編譯

build資料夾裡可以找到GLFW.sln檔案,用Visual Studio 2015開啟。因為CMake已經配置好了專案,所以我們直接點選Build Solution(生成解決方案)按鈕,然後編譯的庫glfw3.lib(注意我們用的是第3版)就會出現在src/Debug資料夾內。

庫生成完畢之後,我們需要讓IDE知道庫和標頭檔案的位置。有兩種方法:

  1. 找到IDE或者編譯器的/lib/include資料夾,新增GLFW的include資料夾裡的檔案到IDE的/include資料夾裡去。用類似的方法,將glfw3.lib新增到/lib資料夾裡去。雖然這樣能工作,但這不是推薦的方式,因為這樣會讓你很難去管理庫和include檔案,而且重新安裝IDE或編譯器可能會導致這些檔案丟失。
  2. 推薦的方式是建立一個新的目錄包含所有的第三方庫檔案和標頭檔案,並且在你的IDE或編譯器中指定這些資料夾。我個人會使用一個單獨的資料夾,裡面包含LibsInclude資料夾,在這裡存放OpenGL工程用到的所有第三方庫和標頭檔案。這樣我的所有第三方庫都在同一個位置(並且可以共享至多臺電腦)。然而這要求你每次新建一個工程時都需要告訴IDE/編譯器在哪能找到這些目錄。

完成上面步驟後,我們就可以使用GLFW建立我們的第一個OpenGL工程了!

我們的第一個工程

首先,開啟Visual Studio,建立一個新的專案。如果VS提供了多個選項,選擇Visual C++,然後選擇Empty Project(空專案)(別忘了給你的專案起一個合適的名字)。現在我們終於有一個空的工作空間了,開始建立我們第一個OpenGL程式吧!

連結

為了使我們的程式使用GLFW,我們需要把GLFW庫連結(Link)進工程。這可以通過在連結器的設定裡指定我們要使用glfw3.lib來完成,但是由於我們將第三方庫放在另外的目錄中,我們的工程還不知道在哪尋找這個檔案。於是我們首先需要將我們放第三方庫的目錄新增進設定。

要新增這些目錄(需要VS搜尋庫和include檔案的地方),我們首先進入Project Properties(工程屬性,在解決方案窗口裡右鍵專案),然後選擇VC++ Directories(VC++ 目錄)選項卡(如下圖)。在下面的兩欄新增目錄:

這裡你可以把自己的目錄加進去,讓工程知道到哪去搜索。你需要手動把目錄加在後面,也可以點選需要的位置字串,選擇選項,之後會出現類似下面這幅圖的介面,圖是選擇Include Directories(包含目錄)時的介面:

這裡可以新增任意多個目錄,IDE會從這些目錄裡尋找標頭檔案。所以只要你將GLFW的Include資料夾加進路徑中,你就可以使用<GLFW/..>來引用標頭檔案。庫資料夾也是一樣的。

現在VS可以找到所需的所有檔案了。最後需要在Linker(連結器)選項卡里的Input(輸入)選項卡里新增glfw3.lib這個檔案:

要連結一個庫我們必須告訴連結器它的檔名。庫名字是glfw3.lib,我們把它加到Additional Dependencies(附加依賴項)欄位中(手動或者使用選項都可以)。這樣GLFW在編譯的時候就會被連結進來了。除了GLFW之外,你還需要新增一個連結條目連結到OpenGL的庫,但是這個庫可能因為系統的不同而有一些差別。

Windows上的OpenGL庫

如果你是Windows平臺,opengl32.lib已經包含在Microsoft SDK裡了,它在Visual Studio安裝的時候就預設安裝了。由於這篇教程用的是VS編譯器,並且是在Windows作業系統上,我們只需將opengl32.lib新增進聯結器設定裡就行了。

Linux上的OpenGL庫

在Linux下你需要連結libGL.so庫檔案,這需要新增-lGL到你的連結器設定中。如果找不到這個庫你可能需要安裝Mesa,NVidia或AMD的開發包,這部分因平臺而異(而且我也不熟悉Linux)就不仔細講解了。

接下來,如果你已經新增GLFW和OpenGL庫到聯結器設定中,你可以用如下方式新增GLFW標頭檔案:

#include <GLFW\glfw3.h>

對於用GCC編譯的Linux使用者建議使用這個命令列選項-lGLEW -lglfw3 -lGL -lX11 -lpthread -lXrandr -lXi。沒有正確連結相應的庫會產生 undefined reference (未定義的引用) 這個錯誤。

GLFW的安裝與配置就到此為止。

GLAD

到這裡還沒有結束,我們仍然還有一件事要做。因為OpenGL只是一個標準/規範,具體的實現是由驅動開發商針對特定顯示卡實現的。由於OpenGL驅動版本眾多,它大多數函式的位置都無法在編譯時確定下來,需要在執行時查詢。所以任務就落在了開發者身上,開發者需要在執行時獲取函式地址並將其儲存在一個函式指標中供以後使用。取得地址的方法因平臺而異,在Windows上會是類似這樣:

// 定義函式原型
typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*);
// 找到正確的函式並賦值給函式指標
GL_GENBUFFERS glGenBuffers  = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");
// 現在函式可以被正常呼叫了
GLuint buffer;
glGenBuffers(1, &buffer);

你可以看到程式碼非常複雜,而且很繁瑣,我們需要對每個可能使用的函式都要重複這個過程。幸運的是,有些庫能簡化此過程,其中GLAD是目前最新,也是最流行的庫。

配置GLAD

GLAD是一個開源的庫,它能解決我們上面提到的那個繁瑣的問題。GLAD的配置與大多數的開源庫有些許的不同,GLAD使用了一個線上服務。在這裡我們能夠告訴GLAD需要定義的OpenGL版本,並且根據這個版本載入所有相關的OpenGL函式。

開啟GLAD的線上服務,將語言(Language)設定為C/C++,在API選項中,選擇3.3以上的OpenGL(gl)版本(我們的教程中將使用3.3版本,但更新的版本也能正常工作)。之後將模式(Profile)設定為Core,並且保證生成載入器(Generate a loader)的選項是選中的。現在可以先(暫時)忽略拓展(Extensions)中的內容。都選擇完之後,點選生成(Generate)按鈕來生成庫檔案。

GLAD現在應該提供給你了一個zip壓縮檔案,包含兩個標頭檔案目錄,和一個glad.c檔案。將兩個標頭檔案目錄(gladKHR)複製到你的Include資料夾中(或者增加一個額外的專案指向這些目錄),並新增glad.c檔案到你的工程中。

經過前面的這些步驟之後,你就應該可以將以下的指令加到你的檔案頂部了:

#include <glad/glad.h> 

點選編譯按鈕應該不會給你提示任何的錯誤,到這裡我們就已經準備好繼續學習下一節去真正使用GLFW和GLAD來設定OpenGL上下文並建立一個視窗了。記得確保你的標頭檔案和庫檔案的目錄設定正確,以及連結器裡引用的庫檔名正確。如果仍然遇到錯誤,可以先看一下評論有沒有人遇到類似的問題,請參考額外資源中的例子或者在下面的評論區提問。

附加資源

  • GLFW: Window Guide:GLFW官方的配置GLFW視窗的指南。
  • Building applications:提供了很多編譯或連結相關的資訊和一大列錯誤及對應的解決方案。
  • GLFW with Code::Blocks:使用Code::Blocks IDE編譯GLFW。
  • Running CMake:簡要的介紹如何在Windows和Linux上使用CMake。
  • Writing a build system under Linux:Wouter Verholst寫的一個autotools的教程,講的是如何在Linux上編寫構建系統,尤其是針對這些教程。
  • Polytonic/Glitter:一個簡單的樣板專案,它已經提前配置了所有相關的庫;如果你想要很方便地搞到一個LearnOpenGL教程的範例工程,這也是很不錯的。