文章目錄
- GLFW
- 獲取 GLFW
- GLAD
- 獲取 GLAD
- 在 Xcode 中配置下載好的 GLFW 和 GLAD
- 配置流程
- 檢測是否配置成功
- 無關配置的題外話——Xcode 下安全的刪除移動操作
GLFW
Graphics Library Framework(圖形庫框架),可以讓我們通過其封裝好的 通用API 來正確創建 OpenGL context(上下文)
并顯示出一個簡單的 窗口
。
如果沒有這個跨平臺工具,那么我們在 windows 上創建 OpenGL窗口 時需要調用顯卡中提供的 windows 使用的 API,而在 Mac 上創建窗口時需要 MacOS 的 API。
獲取 GLFW
從官網上下載GLFW macOS下64位二進制文件
GLAD
因為 OpenGL 只是一個標準/規范,驅動開發商針對不同顯卡有不同的具體實現,導致 OpenGL 驅動版本過于龐雜,大多數函數的位置都無法在編譯時確定下來,需要在運行時查詢。 因此開發者需要在運行時獲取函數地址并將其保存在一個函數指針中供以后使用。
這里來看一個 LearnOpenGL CN 中所舉的 Windows 下獲取函數地址的例子:
// 定義函數原型
typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*);
// 找到正確的函數并賦值給函數指針
GL_GENBUFFERS glGenBuffers = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");
// 現在函數可以被正常調用了
GLuint buffer;
glGenBuffers(1, &buffer);
對于開發人員而言,每使用一個函數就要經歷這樣的尋址過程無疑是極其痛苦的,因此需要通過 GLAD 庫加載所有OpenGL函數指針,來簡化使用函數的流程。
獲取 GLAD
打開 GLAD 的在線服務:
- 將
Language
設置為C/C++
; - 在
API
選項中,選擇3.3
以上的 OpenGL(gl)版本(更新的版本也能用); - 之后將
模式(Profile)
設置為Core
。Compatibility
兼容舊版本,包含低版本中的 API 。Core
只包含當前版本必須支持的 API ,不考慮向下兼容舊版本,更為輕巧。
- 選中
生成加載器(Generate a loader)
選項。 - 可以先(暫時)忽略
擴展(Extensions)
中的內容。 - 點擊
生成(Generate)
按鈕來生成庫文件。
下載得到一個 zip
壓縮文件,包含兩個頭文件目錄,里面分別放著一個和目錄同名的 .h
文件,和一個放著 glad.c
文件的 src
目錄:
在 Xcode 中配置下載好的 GLFW 和 GLAD
配置流程
- 新建項目。
- 選擇
Command Line Tool
。
- 項目名稱隨便起,這里我起名為
OpenGL
。
- 項目所在位置自己選擇,不影響后續配置。
- 接下來通過如圖所示流程配置 Header Search Paths(頭文件搜索路徑)。【當然,初次配置時 Header Search Paths 對應的路徑為空,圖中路徑不為空是因為我配置好了】:
- 雙擊紅框中標注的地方,從訪達中拖拽下載好的
glad/include文件夾
與glfw-3.3.7.bin.MACOS/include文件夾
到彈出的方框中(對于這兩個文件夾在訪達中的所在位置,你可能與我不一樣,因此按照你自己放置的路徑來配置即可),配置頭文件搜索路徑:
拖動添加:
- 在
main.cpp
文件中添加以下代碼,注意添加時兩個 include 語句的順序不能改變:
#include <glad/glad.h>
#include <GLFW/glfw3.h>
請確認是在包含 GLFW 的頭文件之前包含了 GLAD 的頭文件。GLAD 的頭文件包含了正確的 OpenGL 頭文件(例如GL/gl.h),所以需要在其它依賴于 OpenGL 的頭文件之前包含 GLAD。
- 點擊運行按鈕(紅框標注),提示構建成功,則表明頭文件搜索路徑添加成功,已經可以使用 GLFW 和 GLAD 的頭文件:
- 根據下圖順序查看三個文件是否分別被添加進黃框所示部分,即可核驗是否成功鏈接(Link)添加的文件
libglfw3.a
、libglfw3.dylib
(靜態庫、動態庫兩者添加其一即可),以及glad.c
是否參與編譯:
- 最好加上這兩個框架,Xcode有可能會報框架缺失的錯誤,點“+”搜索名字添加即可:
檢測是否配置成功
將下面的代碼復制到 main.cpp 中并運行,如果能彈出一個墨綠色的窗口即證明配置成功。
以下代碼源于 LearnOpenGL CN的創建窗口 ,代碼中注釋不夠細致,如果不懂可以閱讀文檔了解更多。
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>// 對窗口注冊一個回調函數(Callback Function),它會在每次窗口大小被調整的時候被調用。
// 參數:window - 被改變大小的窗口,width、height-窗口的新維度。
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{// 改變視口大小的函數glViewport(0, 0, width, height);
}// 實現輸入控制的函數
void processInput(GLFWwindow *window)
{// glfwGetKey兩個參數:窗口,按鍵// 沒有被按下返回 GLFW_PRESSstd::cout << "是否點擊ESC?" << std::endl;std::cout << glfwGetKey(window, GLFW_KEY_ESCAPE) << std::endl;if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)// 被按下則將 WindowShouldClose 屬性置為 true// 以便于關閉 渲染循環glfwSetWindowShouldClose(window, true);
}int main()
{glfwInit(); // 初始化GLFW// glfwWindowHint函數的第一個參數代表選項的名稱// 第二個參數接受一個整型,用來設置這個選項的值// 將主版本號(Major)和次版本號(Minor)都設為3glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);// 使用的是核心模式(Core-profile)glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);// 參數依次為:寬、高、窗口的名稱,顯示器用于全屏模式,設為NULL是為窗口// 窗口的上下文為共享資源,NULL為不共享資源GLFWwindow* window = glfwCreateWindow(800, 600, "FirstWindow", NULL, NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;// 釋放空間,防止內存溢出glfwTerminate();return -1;}// 創建完畢之后,需要讓window的context成為當前線程的current contextglfwMakeContextCurrent(window);// glfwGetProcAddress是glfw提供的用來加載 系統相關的OpenGL函數指針地址 的函數// 用gladLoadGLLoader函數根據使用者的系統定義了正確的函數if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}// 告訴OpenGL渲染窗口的尺寸大小,即視口(Viewport)// 這樣OpenGL才只能知道怎樣根據窗口大小顯示數據和坐標// 調用glViewport函數來設置窗口的維度(Dimension)// 前兩個參數控制窗口左下角的位置。第三個和第四個參數控制渲染窗口的寬度和高度(像素)glViewport(0, 0, 800, 600);// 窗口大小改變時視口也要隨之改變,這通過對窗口注冊 framebuffer_size_callback 實現。// 它會在每次窗口大小被調整時調用glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);/* 渲染循環(Render Loop) */// glfwWindowShouldClose 檢查一次GLFW是否被要求退出// 為true時渲染循環結束while(!glfwWindowShouldClose(window)){// 監測鍵盤輸入processInput(window);/* 渲染 */// 狀態設置函數,設置清空屏幕所用的顏色glClearColor(0.2f, 0.3f, 0.3f, 1.0f);// 狀態使用函數,使用設定好的顏色來清除舊的顏色緩沖glClear(GL_COLOR_BUFFER_BIT);// 上面兩種函數起到的作用也可以用 glClearBufferfv 來現實/*GLfloat color[] = {0.2, 0.3, 0.3, 1.0};glClearBufferfv(GL_COLOR, 0, color);*/// glfwSwapBuffers 交換顏色緩沖,用來繪制并作為輸出顯示在屏幕glfwSwapBuffers(window);// glfwPollEvents 檢查是否有觸發事件glfwPollEvents();}glfwTerminate();return 0;
}
運行結果:
無關配置的題外話——Xcode 下安全的刪除移動操作
接下來要講的一點與配置關系不大,但是也給初使用 Xcode 的我帶來了不小的麻煩。不同于 Windows 下的操作習慣,在 macOS 中盡量在訪達中對文件進行移動、刪除等操作,而非直接拖拽到 Xcode 的樹形目錄中進行移動,亦或直接在樹形目錄中進行刪除。舉個例子:
- 比如在當前項目(OpenGL)的同級目錄下我新建了一個
test
文件夾,并且其中有文件test.sh
:
- 而后我將它通過訪達拖拽移動到 OpenGL 目錄下:
- 此時如果通過 Xcode 樹形目錄進行刪除:
- 會詢問刪除方式,兩種方式的區別詳見本篇文章:
- Move to Trash:刪除文件內容到廢紙簍(此時的文件內容不在工程中,但是文件夾還是會在工程中):
刪除前:
刪除后:
- Reremove reference:移除文件的引用(只是刪除引用,文件內容都還在工程中),后續如果添加相同文件會彈出“要添加的文件已存在”的報錯提示,需要在訪達中將上次僅刪除引用的文件完全刪除。
刪除前同上。
刪除后:
- 不論是
Reremove reference
還是Move to Trash
他們的文件夾都會在工程中(如果沒有清除,下次添加重名的工程文件會彈出警告)。
PS:還遇到過刪除 OpenGL 目錄下的 test 文件夾,結果導致與 OpenGL 同級的 test 文件夾也被刪除的情況,但后來無法復現,因此在這里無法貼圖證明。總而言之,對 macOS 使用尚不熟練時,盡量使用訪達對文件進行移動刪除操作(通過拖拽獲得文件路徑是簡單且安全的方法,可以使用),即使是對 Xcode 樹形目錄進行操作也請盡可能通過 Show in Finder
跳轉到訪達中,以避免出現不必要的錯誤與文件損失。