一、簡介
最近,馬三買了兩本有關於“計算機圖形學”的書籍,准備在工作之余鼓搗鼓搗圖形學和OpenGL編程,提升自己的價值(奔着學完能漲一波工資去的)。俗話說得好,“工欲善其事,必先利其器”。想學習圖形學和OpenGL編程必須先把開發環境搭建好,而馬三只是在上學的時候稍稍做了一些基於Android平台的OpenGL開發學習,並沒有搭建過OpenGL開發環境。因此在搭建過程中頗廢了一番周折,也查閱了不少資料才算搭建成功,特此記錄一下搭建過程,以備不時之需。
二、搭建環境
1.VS2017
這個不必多說了,基本做過開發的都會安裝這個“宇宙最強IDE”了。直接去官網下載安裝助手,然后安裝即可。
2.GLFW庫
正常來說開發進行OpenGL開發的話,glut庫是必不可少的,但是馬三在網上一搜啊,發現glut這個庫過時了,現在比較新版的GLFW完全可以替代它。關於這些名詞相關的具體介紹,我們會在稍后仔細介紹一下,我們還是先去 GLFW官網 把庫下載下來。
圖1:GLFW官網下載示意圖
3.GLEW庫
接着我們還需要下載GLEW庫,眾所周知,OpenGL只是一個標准,不同的顯卡公司在不同的平台下對其有不同的實現,同時也是發布一些只支持自家顯卡的拓展函數。通過引入glew庫,我們完全可以不用理睬這些細節,安心寫代碼就好了。
同樣還是去 GLEW的官網 下載我們所需要的內容:
圖2:GLEW官網下載示意圖
對於以上的這兩個庫和源代碼,馬三已經下載了寫博客時的最新版本,並打成了壓縮包,方便各位下載。下載請移步。
4.安裝並測試運行
解壓我們下載的兩個庫,並在VS2017里面新建一個C++空項目。如果創建的是控制台或者其他項目的話,vs工具會自動幫你添加一個stdafx.h的預編譯頭,你必須在源文件的開頭寫上#include “stdafx.h”相關語句,而且之后引入glew,glfw包會有莫名其妙的錯誤。所以創建一個空項目。如下如所示:
圖3:解壓后的庫
圖4:創建新的空項目
然后,點擊“解決方案資源管理器”,右鍵點擊源文件,添加新項,創建.cpp源文件,可以隨便命個名,比如main.cpp:
圖5:新建源文件
接着,右鍵點擊項目,在彈出的選項中,單擊 “屬性”,點擊“VC++目錄”,然后選擇“包含目錄”選項,單擊下拉菜單中的“編輯”:
圖5、6項目屬性編輯
接着我們在新打開的窗口中添加頭文件。分別添加下載的glew和glfw文件夾下的include文件夾(include文件夾下是我們需要的頭文件),並點擊“確定”:
圖7:include頭文件
之后,再繼續添加庫文件到項目中,頭文件通常是函數的聲明,而函數的實現一般都放在了庫中,二者相輔相成,只有都正確的引入了,才能正常工作。其對應的路徑就是glew和glfw文件夾下的lib文件夾:
有兩點需要我們特別注意一下:
- 當添加glew時,當選到lib文件夾后請繼續選擇,lib->Release->Win32,請選擇Win32后點擊“選擇文件夾”(x64會有莫名其妙的問題)
- 當添加glfw時,低版本請選擇對應版本,2015以上版本請選擇“lib-vc2015”。馬三用的是2017所以選擇lib-vc2015
圖8:lib庫文件
只包含了庫文件還不行,我們需要手動指定一下。配置鏈接器:
圖9:鏈接器配置
在里面手動加入如下選項,行與行之間請按回車,opengl32.lib是系統自帶的。glfw3.lib,glew32s.lib 是我們下載的庫中的,其實就是之前包含的lib文件夾下的文件名(去掉glew32.lib):
opengl32.lib
glfw3.lib
glew32s.lib
圖10:編輯鏈接器配置
經過上面一系列的繁瑣的操作,我們的OpenGL開發環境基本也算搭建完成了,下面讓我們在main.cpp中添加一些代碼測試一下,環境是否搭建成功,我們的程序是否能夠跑起來。在main.cpp中加入如下測試代碼:
1 #include<iostream> 2 #define GLEW_STATIC 3 #include <GL/glew.h> 4 #include <GLFW\glfw3.h> 5 6 using namespace std; 7 8 int main(int argc, char** argv[]) 9 { 10 /*glewExperimental = GL_TRUE; 11 if (glewInit()!=GLEW_OK) 12 { 13 cout << "failed to initalize GLEW" << endl; 14 return -1; 15 }*/ 16 17 glfwInit();//初始化 18 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW 19 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW 20 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// 21 glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); 22 23 GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr); 24 if (window == nullptr) 25 { 26 cout << "Failed to create GLFW window" << endl; 27 glfwTerminate(); 28 return -1; 29 } 30 glfwMakeContextCurrent(window); 31 while (!glfwWindowShouldClose(window)) 32 { 33 glfwPollEvents(); 34 glfwSwapBuffers(window); 35 } 36 glfwTerminate(); 37 return 0; 38 39 40 }
然后,點擊調試,如果成功了的話可以看到類似於下面的這種窗口,其實是初始化了一個空的OpenGL窗口:
圖11:初始化OpenGL窗口
但是我們會發現在vs的錯誤列表窗口中出現了一條警告:“警告 LNK4098 默認庫“MSVCRT”與其他庫的使用沖突;請使用 /NODEFAULTLIB:library BuildEnv F:\xxxx”
這個警告也是比較好解決的,打開我們之前配置鏈接器的那個頁面,然后選擇忽略特定庫選項,並編輯。在其中加入 "MSVCRT.lib",然后然后點擊確定,之后就會發現警告消失不見了。如果以后還有其他的類似的庫沖突,我們可以使用同樣的方法解決。
圖12:解決庫沖突
三、一些名詞概念
盡管我們已經成功的搭建了OpenGL開發環境,但是相信此時一定有不少小伙伴和馬三一樣對OpenGL開發中的一些庫和名詞處於蒙蔽狀態。馬三也是搜集了這些名詞的資料和大家一起分享一下。
1.OpenGL是什么
OpenGL函數庫相關的API有核心庫(gl),實用庫(glu),輔助庫(aux)、實用工具庫(glut),窗口庫(glx、agl、wgl)和擴展函數庫等。gl是核心,glu是對gl的部分封裝。glx、agl、wgl 是針對不同窗口系統的函數。glut是為跨平台的OpenGL程序的工具包,比aux功能強大(aux很大程度上已經被glut庫取代。)。擴展函數庫是硬件廠商為實現硬件更新利用OpenGL的擴展機制開發的函數。
2.gult:OpenGL工具庫(OpenGL Utility Toolkit)
這部分函數以glut開頭,主要包括窗口操作函數,窗口初始化、窗口大小、窗口位置等函數;回調函數:響應刷新消息、鍵盤消息、鼠標消息、定時器函數等;創建復雜的三維物體;菜單函數;程序運行函數。gult對應的開源實現是freegult,freegult官網請移步。
3.glew庫是什么
GLUT或者FREEGLUT主要是1.0的基本函數功能;GLEW是使用OPENGL2.0之后的一個工具函數。不同的顯卡公司,也會發布一些只有自家顯卡才支持的擴展函數,你要想用這數函數,不得不去尋找最新的glext.h,有了GLEW擴展庫,你就再也不用為找不到函數的接口而煩惱,因為GLEW能自動識別你的平台所支持的全部OpenGL高級擴展函數。也就是說,只要包含一個glew.h頭文件,你就能使用gl,glu,glext,wgl,glx的全部函數。glew庫提供高版本 gl 函數的支持。如果不嫌麻煩的話,也可以手寫函數指針,來判斷各個 opengl 高版本函數是否支持,但是 glew 庫 做了大大的簡化,使得 opengl 各個版本的函數像原生函數一樣,可以隨意調用。
4.glfw
GLFW無愧於其號稱的lightweight的OpenGL框架,的確是除了跨平台必要做的事情都沒有做,所以一個頭文件,很少量的API,就完成了任務。GLFW的開發目的是用於替代glut的,從代碼和功能上來看,我想它已經完全的完成了任務。一個輕量級的,開源的,跨平台的library。支持OpenGL及OpenGL ES,用來管理窗口,讀取輸入,處理事件等。因為OpenGL沒有窗口管理的功能,所以很多熱心的人寫了工具來支持這些功能,比如早期的glut,現在的freeglut等。
那么GLFW有何優勢呢?glut太老了,最后一個版本還是90年代的。freeglut完全兼容glut,算是glut的代替品,功能齊全,但是bug太多。因此,GLFW應運而生。
綜上所述:
1.glfw是glut的升級和改進
2.glew包含了OpenGL所需的核心
5.glad庫
目前網上的一些教程還有使用glad庫的,glad與glew有什么區別呢?簡單說glad是glew的升級版。用哪個都行。glew比較老,glad比較新。下面簡單介紹一些glad如何使用:
glad有一個在線服務,直接下下來就可以用了(編譯好的),將語言(Language)設置為C/C++,在API選項中,選擇3.3以上的OpenGL版本(3.3是可編程管線版本,但更新的版本也能正常工作)。之后將模式(Profile)設置為Core,並且保證生成加載器(Generate a loader)的選項是選中的。現在可以先(暫時)忽略拓展(Extensions)中的內容。都選擇完之后,點擊生成(Generate)按鈕來生成庫文件。
下載到本地是個壓縮文件,解壓完成后會有這樣的文件夾結構:
圖13:glad文件目錄
包含兩個頭文件目錄(內有頭文件glad.h和khrplatform.h),和一個src文件夾下的glad.c文件。只需要將原來的第五步的 VC++目錄 -> 包含目錄 中的glew的include文件夾改成glad的include文件夾即可。后面的步驟glad都不需要。
然后將glad.c文件復制到源文件夾下:
圖14:glad復制到源文件夾
注意glad.c文件這時候或者編譯的時候會出錯,首先看看glad.c的include的路徑是不是對的,有時候包含目錄文件夾路徑不一樣,你要改成你自己配置的glad路徑(就是之前VC++目錄配置的路徑)。
然后需要將我們的測試代碼換成如下這段:

1 #include <glad/glad.h> 2 #include <GLFW/glfw3.h> 3 4 #include <iostream> 5 6 const unsigned int SCR_WIDTH = 800; 7 const unsigned int SCR_HEIGHT = 600; 8 9 int main() 10 { 11 glfwInit(); 12 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 13 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 14 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 15 16 GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); 17 if (window == NULL) 18 { 19 std::cout << "Failed to create GLFW window" << std::endl; 20 glfwTerminate(); 21 return -1; 22 } 23 glfwMakeContextCurrent(window); 24 25 if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) 26 { 27 std::cout << "Failed to initialize GLAD" << std::endl; 28 return -1; 29 } 30 31 while (!glfwWindowShouldClose(window)) 32 { 33 34 glClearColor(0.2f, 0.3f, 0.3f, 1.0f); 35 glClear(GL_COLOR_BUFFER_BIT); 36 37 glfwSwapBuffers(window); 38 glfwPollEvents(); 39 } 40 41 glfwTerminate(); 42 return 0;
四、總結
在本篇博客中,馬三和大家一起從頭開始搭建了一個OpenGL開發環境,並且了解了一些OpenGL的概念與名詞。接下來馬三將會一邊學習計算機圖形學和OpenGL,一邊隨時隨地的把想法記錄下來與大家分享~
參考資料:
如果覺得本篇博客對您有幫助,可以掃碼小小地鼓勵下馬三,馬三會寫出更多的好文章,支持微信和支付寶喲!
作者:馬三小伙兒
出處:https://www.cnblogs.com/msxh/p/9622617.html
請尊重別人的勞動成果,讓分享成為一種美德,歡迎轉載。另外,文章在表述和代碼方面如有不妥之處,歡迎批評指正。留下你的腳印,歡迎評論!