前言
上一篇隨筆介紹了我的電腦,同時也介紹了 Ubuntu 20.10 系統的安裝和美化。這一篇,我將正式開始 OpenGL 之旅。使用 Ubuntu 來進行開發,不僅僅只是因為我對 Linux 桌面比較熟悉,其實我對 Windows 也很熟悉,主要還是因為在 Linux 系統下搭建 OpenGL 的開發環境確實是太方便了。在 Windows 下開發 OpenGL,每用到一個庫,我們都要單獨去搜索和下載,然后在 Visual Studio 中進行設置,很繁瑣。在 Ubuntu 中,安裝這些庫,就是一條命令的事,下面詳細論述。
搭建 OpenGL 的開發環境
學 OpenGL,C/C++ 應該是首選,所以先安裝 C/C++ 的開發環境,無論是選擇 GCC,還是選擇 CLang,在 Ubuntu 中就是一條命令的事,我這里選 GCC。在 Ubuntu 中,可以直接安裝 build-essential,更省事。命令如下:
sudo apt install build-essential
OpenGL 不提供和 GUI 相關的 API,所以 OpenGL 不能處理諸如創建窗口、處理用戶的鍵盤鼠標輸入這樣的任務。這時,我們需要 GLFW。使用 GLFW 庫,我們可以簡化搭建 OpenGL 程序框架的任務,同時還可以輕松獲得跨平台的功能。安裝 GLFW 也是一條命令的事:
sudo apt install libglfw3 libglfw3-dev
除此之外,我們還需要 GLEW。有了GLEW 擴展庫,就再也不用為找不到函數的接口而煩惱了,因為GLEW能自動識別平台所支持的全部 OpenGL 高級擴展涵數。安裝命令如下:
sudo apt install libglew2.1 libglew-dev
另外,在寫 OpenGL 程序的過程中,會經常需要進行向量、矩陣的計算,所以有一個順手的數學庫是很重要的,我這里選擇 GLM。安裝命令如下:
sudo apt install libglm-dev
學會了 OpenGL 的基本概念后,當然會忍不住想加載個 3D 模型看看效果,這時候,就可以考慮使用 Assimp 庫了。安裝命令如下:
sudo apt install assimp-utils libassimp5 libassimp-dev
assimp-utils 包提供了一個assimp
命令,使用該命令可以顯示 Assimp 庫支持哪些格式的 3D 模型文件,也可以使用該命令顯示 3D 模型文件的詳細信息,如下圖:
當然,3D 的東西,還是應該用可視化的方式看起來更直觀一些。好在,Linux 中可用的 3D 建模動畫軟件有 Blender。安裝起來也只是一條命令的事:
sudo apt install blender
下面,讓大家看一下我的老婆,用的就是 Blender:
最簡單的 OpenGL 程序框架
下面,開始寫我們的第一個 OpenGL 程序,如下:
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
const int SCR_WIDTH = 1920;
const int SCR_HEIGHT = 1080;
int main(int argc, char** argv){
glfwInit();
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "StudyOpenGL", nullptr, nullptr);
if (window == NULL)
{
std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if(glewInit() != GLEW_OK){
std::cerr << "Failed to initalize GLEW" << std::endl;
return -1;
}
while (!glfwWindowShouldClose(window))
{
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
這段程序比較短,使用任何編輯器如 vim、gedit 等等都可以。當后面程序變長之后,我選擇使用 Visual Studio Code。我們將這個文件保存為 FirstStep.cpp。編譯執行的命令也很簡單:
g++ FirstStep.cpp -o FirstStep -lGL -lGLEW -lglfw
./FirstStep
就可以看到我們的第一個 OpenGL 窗口了,目前,它還只是空洞洞的漆黑一片,如下圖:
因為我是 4K 屏,所以即使定義了SCR_WIDTH = 1920
和SCR_HEIGHT = 1080
,窗口看起來也不是特別大。上面那個程序是純 C 版的,等程序變大之后,會在 main() 函數之外遺留很多全局的變量和函數,不是那么清爽,所以常規會使用 C++ 封裝一下,建立一個 App 類,以后要添加鼠標鍵盤輸入的功能也在這個類里面加,建立新程序時,只需要繼承這個類就可以了。App 類的內容如下:
#ifndef __APP_HPP__
#define __APP_HPP__
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
class App{
private:
const int SCR_WIDTH = 1920;
const int SCR_HEIGHT = 1080;
public:
static App* the_app;
App(){
}
virtual void init(){
}
virtual void display(){
}
virtual void run(App* app){
if(the_app != NULL){ //同一時刻,只能有一個App運行
std::cerr << "The the_app is already run." << std::endl;
return;
}
the_app = app;
glfwInit();
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "StudyOpenGL", NULL, NULL);
if (window == NULL)
{
std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return;
}
glfwMakeContextCurrent(window);
if(glewInit() != GLEW_OK){
std::cerr << "Failed to initalize GLEW" << std::endl;
return;
}
init(); //用來准備各種數據
while (!glfwWindowShouldClose(window))
{
display(); //這里才是渲染圖形的主戰場
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
return;
}
};
App* App::the_app = NULL;
#define DECLARE_MAIN(a) \
int main(int argc, const char ** argv) \
{ \
a *app = new a; \
app->run(app); \
delete app; \
return 0; \
}
#endif
把這個文件保存在 include 目錄下,命名為 app.hpp,然后,把之前的 FirstStep.cpp 改成如下內容:
#include "../include/app.hpp"
class MyApp : public App {
private:
public:
void init(){
}
void display(){
}
~MyApp(){
}
};
DECLARE_MAIN(MyApp)
編譯運行,結果是一樣的。以后,只需要把初始化數據的代碼放到 init() 方法中,把渲染圖形的代碼放到 display() 方法中即可。程序運行時,init() 方法只調用一次,而 display() 方法每渲染一幀圖像就調用一次。
OK,到這里,我們的環境就搭建好了。在下一篇隨筆中,我們爭取使用 OpenGL 渲染一點有用的東西。
版權申明
該隨筆由京山游俠在2021年01月27日發布於博客園,引用請注明出處,轉載或出版請聯系博主。QQ郵箱:1841079@qq.com