ubuntu配置opengl環境glfw+glad+glm+stb_image.h+Assimp

Linux和X11的依賴關係

編譯GLFW for X11,您需要安裝X11軟件包,以及GCC和make等基本開發工具。例如,在Ubuntu和其他基於Debian GNU / Linux的發行版上,您需要安裝xorg-dev包,它包含所有X.org標頭包。

sudo apt-get install build-essential
sudo apt-get install libglfw3-dev
sudo apt-get install cmake xorg-dev 
sudo apt-get install libgl1-mesa-dev

GLUT

OpenGL Utilities 是一組建構於 OpenGL Library 之上的工具組,提供許多很方便的函式,使 OpenGL 更強大且更容易使用。安裝OpenGL Utility Toolkit(glut跟glfw作用類似,理論上可以不用安裝):

sudo apt-get install libglut-dev

OpenGL Utility Toolkit 是建立在 OpenGL Utilities 上面的工具箱,除了強化了 OpenGL Utilities 的不足之外,也增加了 OpenGL 對於視窗介面支援。
注意:在這一步的時候,可能會出現以下情況,shell提示:

    Reading package lists... Done
    Building dependency tree
    Reading state information... Done
    E: Unable to locate package libglut-dev

將上述$ sudo apt-get install libglut-dev命令改成$ sudo apt-get install freeglut3-dev即可:

sudo apt-get install freeglut3-dev

GLFW

到GLFW官網下載3.3版本

unzip glfw-3.3.zip
cd glfw-3.3
mkdir build
cd build
#這裏默認cmake是編譯靜態庫的,故添加-DBUILD_SHARED_LIBS=ON使其編譯動態庫
cmake ../ -DBUILD_SHARED_LIBS=ON
make
sudo make install

GLAD

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

GLAD現在應該提供給你了一個zip壓縮文件,包含兩個頭文件目錄,和一個glad.c文件。將兩個頭文件目錄(glad和KHR)複製到你的Include文件夾中(或者增加一個額外的項目指向這些目錄),並添加glad.c文件到你的工程中。
或者將兩個頭文件目錄(glad和KHR)複製到你的Include文件夾中(即/usr/local/include),並添加glad.c文件到稍後的工程中。

unzip glad.zip
cd glad/include
sudo cp -r glad KHR /usr/local/include/

GLM

在這裏插入圖片描述
GLM庫從0.9.9版本起,默認會將矩陣類型初始化爲一個零矩陣(所有元素均爲0),而不是單位矩陣(對角元素爲1,其它元素爲0)。如果你使用的是0.9.9或0.9.9以上的版本,你需要將所有的矩陣初始化改爲 glm::mat4 mat = glm::mat4(1.0f)。

windows

配置GLM:https://blog.csdn.net/Wonz5130/article/details/83116009

linux

中配置GLM:
到gitlab鏈接下載glm 0.9.8.0 版本
解壓,進入glm 0.9.8.0 :
解壓之後,直接用glm文件
要用到GLM直接#include頭文件,如:

// GLEW
#include <glad/glad.h>

// GLFW
#include <GLFW/glfw3.h>

// GLM
#include <glm-master/glm/glm.hpp>
#include <glm-master/glm/gtc/matrix_transform.hpp>
#include <glm-master/glm/gtc/type_ptr.hpp>

// FreeType
#include <freetype2/ft2build.h>
#include FT_FREETYPE_H

// GL includes
#include "stb_image.h"
#include <locale>
#include <codecvt>

freetype2

下載地址,下載需要的版本。
或者命令行下載:

wget http://download.savannah.gnu.org/releases/freetype/freetype-2.4.10.tar.gz
tar zxvf freetype-2.4.10.tar.gz 
cd  freetype-2.4.10
./configure --prefix=/usr/local/freetype 
make -j4
sudo make install

工程引用是添加頭文件路徑和庫路徑

INCLUDEPATH +=  /usr/local/include/freetype2
LIBS += -L/usr/lib/x86_64-linux-gnu
LIBS+= -lfreetype

測試

// System Headers
#include <glad/glad.h>
#include <GLFW/glfw3.h>

// Standard Headers
#include <cstdio>
#include <cstdlib>
#include <iostream>

void framebuffer_size_callback(GLFWwindow* window, int width, int height);//回調函數原型聲明
void processInput(GLFWwindow *window);

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

int main(int argc, char * argv[]) {

    //初始化GLFW
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
#endif
    //創建一個窗口對象
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "FirstGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    //通知GLFW將我們窗口的上下文設置爲當前線程的主上下文
    glfwMakeContextCurrent(window);
    //對窗口註冊一個回調函數,每當窗口改變大小,GLFW會調用這個函數並填充相應的參數供你處理
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    //初始化GLAD用來管理OpenGL的函數指針
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    //渲染循環
    while(!glfwWindowShouldClose(window))
    {
        // 輸入
        processInput(window);

        // 渲染指令
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // 檢查並調用事件,交換緩衝
        glfwSwapBuffers(window);//檢查觸發事件
        glfwPollEvents();    //交換顏色緩衝
    }

    //釋放/刪除之前的分配的所有資源
    glfwTerminate();
    return EXIT_SUCCESS;
}

//輸入控制,檢查用戶是否按下了返回鍵(Esc)
void processInput(GLFWwindow *window)
{
    if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

// 當用戶改變窗口的大小的時候,視口也應該被調整 
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // 注意:對於視網膜(Retina)顯示屏,width和height都會明顯比原輸入值更高一點。
    glViewport(0, 0, width, height);
}

將 glad.c 放在和該 main.cpp 在同一目錄下, 編譯:

g++ -o out main.cpp glad.c -lglfw3 -lGL -lm -lXrandr -lXi -lX11 -lXxf86vm -lpthread -ldl -lXinerama -lXcursor

運行:

./out

或者藉助qt,配置.pro文件:

TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt

SOURCES += \
    test.cpp \
    glad.c

LIBS += -lglfw3 -lGL -lm -lXrandr -lXi -lX11 -lXxf86vm -lpthread -ldl -lXinerama -lXcursor

最終.pro文件:

#opengl
QT += opengl widgets
QT += core gui
TEMPLATE = app
CONFIG += qt opengl warn_on release

LIBS += -lglut
LIBS+= -lGLU
LIBS+= -lGLEW
LIBS+= -lglfw3
LIBS +=-lpthread
LIBS +=-lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor
LIBS+= -ldl
LIBS+= -lfreetype

INCLUDEPATH += /usr/include/freetype2

stb_image.h

使用紋理之前要做的第一件事是把它們加載到我們的應用中。紋理圖像可能被儲存爲各種各樣的格式,每種都有自己的數據結構和排列,所以我們如何才能把這些圖像加載到應用中呢?一個解決方案是選一個需要的文件格式,比如.PNG,然後自己寫一個圖像加載器,把圖像轉化爲字節序列。寫自己的圖像加載器雖然不難,但仍然挺麻煩的,而且如果要支持更多文件格式呢?你就不得不爲每種你希望支持的格式寫加載器了。

另一個解決方案也許是一種更好的選擇,使用一個支持多種流行格式的圖像加載庫來爲我們解決這個問題。比如說我們要用的stb_image.h庫。

stb_image.h是Sean Barrett的一個非常流行的單頭文件圖像加載庫,它能夠加載大部分流行的文件格式,並且能夠很簡單得整合到你的工程之中。stb_image.h可以在這裏下載。下載這一個頭文件,將它以stb_image.h的名字加入你的工程,並另創建一個新的C++文件,輸入以下代碼:

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

通過定義STB_IMAGE_IMPLEMENTATION,預處理器會修改頭文件,讓其只包含相關的函數定義源碼,等於是將這個頭文件變爲一個 .cpp 文件了。現在只需要在你的程序中包含stb_image.h並編譯就可以了。

Assimp

assimp介紹

一個非常流行的模型導入庫是Assimp,它是Open Asset Import Library(開放的資產導入庫)的縮寫。Assimp能夠導入很多種不同的模型文件格式(並也能夠導出部分的格式),它會將所有的模型數據加載至Assimp的通用數據結構中。當Assimp加載完模型之後,我們就能夠從Assimp的數據結構中提取我們所需的所有數據了。由於Assimp的數據結構保持不變,不論導入的是什麼種類的文件格式,它都能夠將我們從這些不同的文件格式中抽象出來,用同一種方式訪問我們需要的數據。

當使用Assimp導入一個模型的時候,它通常會將整個模型加載進一個場景(Scene)對象,它會包含導入的模型/場景中的所有數據。Assimp會將場景載入爲一系列的節點(Node),每個節點包含了場景對象中所儲存數據的索引,每個節點都可以有任意數量的子節點。Assimp數據結構的(簡化)模型如下:
在這裏插入圖片描述

  • 和材質和網格(Mesh)一樣,所有的場景/模型數據都包含在Scene對象中。Scene對象也包含了場景根節點的引用
  • 場景的Root node(根節點)可能包含子節點(和其它的節點一樣),它會有一系列指向場景對象中mMeshes數組中儲存的網格數據的索引。Scene下的mMeshes數組儲存了真正的Mesh對象,節點中的mMeshes數組保存的只是場景中網格數組的索引
  • 一個Mesh對象本身包含了渲染所需要的所有相關數據,像是頂點位置、法向量、紋理座標、面(Face)和物體的材質。
  • 一個網格包含了多個面。Face代表的是物體的渲染圖元(Primitive)(三角形、方形、點)。一個麪包含了組成圖元的頂點的索引。由於頂點和索引是分開的,使用一個索引緩衝來渲染是非常簡單的(三角形)。
  • 最後,一個網格也包含了一個Material對象,它包含了一些函數能讓我們獲取物體的材質屬性,比如說顏色和紋理貼圖(比如漫反射和鏡面光貼圖)。

所以,我們需要做的第一件事是將一個物體加載到Scene對象中,遍歷節點,獲取對應的Mesh對象(我們需要遞歸搜索每個節點的子節點),並處理每個Mesh對象來獲取頂點數據、索引以及它的材質屬性。最終的結果是一系列的網格數據,我們會將它們包含在一個Model對象中。
在這裏插入圖片描述
我們將創建我們自己的Model和Mesh類來加載並使用剛剛介紹的結構儲存導入後的模型。如果我們想要繪製一個模型,我們不需要將整個模型渲染爲一個整體,只需要渲染組成模型的每個獨立的網格就可以了。然而,在我們開始導入模型之前,我們首先需要將Assimp包含到我們的工程當中。

assimp構建

參考:https://blog.csdn.net/wodownload2/article/details/83410521

在Assimp的下載頁面中選擇相應的版本。此時使用的Assimp版本爲3.1.1。建議自己編譯Assimp庫,因爲它們的預編譯庫在大部分系統上都是不能運行的。

構建Assimp時可能會出現一些問題,解決方案:

  • CMake在讀取配置列表時,不斷報出DirectX庫丟失的錯誤。報錯如下:
    解決方案:參考:https://blog.csdn.net/lady_killer9/article/details/89429092
    在這裏插入圖片描述
    這個問題的解決方案是安裝DirectX SDK,如果你之前沒安裝過的話。你可以從這裏下載SDK
  • 安裝DirectX SDK時,可能遇到一個錯誤碼爲s1023的錯誤。這種情況下,請在安裝SDK之前根據這個先卸載C++ Redistributable package(s)(到控制面板中去卸載,安裝完DirectX SDK後,將卸載的c++ Redistributable再安裝好)。
  • 一旦配置完成,你就可以生成解決方案文件了,打開解決方案文件並編譯Assimp庫(可以編譯爲Debug版本也可以編譯爲Release版本,只要能工作就行)。
  • 使用默認配置構建的Assimp是一個動態庫(Dynamic Library),所以我們需要包含所生成的assimp.dll文件以及程序的二進制文件。你可以簡單地將DLL複製到我們程序可執行文件的同一目錄中。
  • Assimp編譯之後,生成的庫和DLL文件位於code/Debug或者code/Release文件夾中。
  • 接着把編譯好的LIB文件和DLL文件拷貝到工程的相應目錄下,並在解決方案中鏈接它們。並且記得把Assimp的頭文件也複製到你的include目錄中(頭文件可以在從Assimp中下載的include目錄裏找到)。

如果你想讓Assimp使用多線程來獲得更高的性能,你可以使用Boost庫來編譯Assimp。你可以在它們的安裝頁面找到完整的安裝介紹。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章