張肇同
【摘 要】在機(jī)器人仿真軟件開發(fā)、三維視景建模等領(lǐng)域,通常需要讀取三維建模,這些模型大都由專業(yè)的三維建模軟件生成,具有特定的文件格式。本文基于OpenGL,對此過程中的模型導(dǎo)入與動態(tài)觀察部分進(jìn)行研究。在VS2017環(huán)境下,通過OpenGL與Assimp實現(xiàn)三維模型數(shù)據(jù)文件的可視化,使人們可以獲取到模型特定數(shù)據(jù),并可直觀地看到模型,為其余工作奠定基礎(chǔ)。
【關(guān)鍵詞】OpenGL;Assimp;模型可視化;動態(tài)觀察
0 引言
目前,許多優(yōu)秀的三維建模軟件如CATIA、UG、Pro/E等,可以方便地建立各種復(fù)雜物體模型,但除了軟件所給出的功能外,很難對模型進(jìn)行控制和操作[1]。OpenGL則更容易實現(xiàn)模型的變換、紋理、交互操作等,但是卻沒有提供CATIA、UG等建模軟件中用于建立復(fù)雜三維模型的高級命令,只提供了基本的集合圖元(如點、線、多邊形)的繪制命令[2]。因此,若能將三維建模軟件輸出的模型文件,在OpenGL中進(jìn)行“加工”,可以更好地解決實際問題。
1 模型讀取與繪制方法
考慮到各平臺文件格式不同,為了增強(qiáng)通用性,我們選擇通過Assimp庫輔助模型讀取工作,這樣可讀入十余種不同格式的主流模型文件,增強(qiáng)了通用性,方便了后續(xù)工作。
1.1 Assimp概述
Assimp(Open Asset Import Library)是開源圖形庫,它會將所有的模型數(shù)據(jù)加載至Assimp的通用數(shù)據(jù)結(jié)構(gòu)中[3]。當(dāng)Assimp加載完模型之后,我們就能夠從Assimp的數(shù)據(jù)結(jié)構(gòu)中提取我們所需的所有數(shù)據(jù)了。由于Assimp的數(shù)據(jù)結(jié)構(gòu)保持不變,不論導(dǎo)入的是什么種類的文件格式,它都能夠?qū)⒛P蛿?shù)據(jù)從這些不同文件格式中抽象出來,用同一種方式訪問所需數(shù)據(jù)。
當(dāng)使用Assimp導(dǎo)入一個模型的時候,它通常會將整個模型加載進(jìn)一個場景對象,它會包含導(dǎo)入的模型中的所有數(shù)據(jù)。Assimp會將場景載入為一系列的節(jié)點,每個節(jié)點包含了場景對象中所儲存數(shù)據(jù)的索引,每個節(jié)點都可以由任意數(shù)量的子節(jié)點。
一個網(wǎng)格對象本身包含了渲染所需要的所有相關(guān)數(shù)據(jù),如頂點、法向量、紋理坐標(biāo)、面和材質(zhì)等。一個網(wǎng)格包含了多個面,一個面包含了組成圖元的頂點索引。由于頂點數(shù)據(jù)和頂點索引是分開的,使用一個索引緩沖來渲染是非常方便的。
1.2 場景繪制方式
現(xiàn)在,我們可以根據(jù)場景的結(jié)構(gòu),讀取場景對象中的數(shù)據(jù)并繪制模型。為了更加系統(tǒng)的進(jìn)行場景繪制,我們構(gòu)建了Model類與Mesh類,分別對應(yīng)于模型結(jié)構(gòu)與網(wǎng)格結(jié)構(gòu):
class Model{
public:
Model(char* path){ };
void Draw(Shader shader);
private:
vector
void loadModel( string path);
void processNode(aiNode* node, const aiScene* scene);
Mesh processMesh( aiMesh* mesh, const aiScene* scene);
};
class Mesh{
public:
vector
vector
GLuint VAO;
Mesh(vector
void Draw(Shader shader);
private:
GLuint VBO, EBO;
void setupMesh();
};
1.2.1 模型讀取
首先,讀取給定路徑的模型文件并加載到Scene對象。除了加載文件之外,我們還可以設(shè)定一些選項強(qiáng)制性對導(dǎo)入的數(shù)據(jù)做一些額外的計算或操作。
1.2.2 處理模型節(jié)點
我們首先檢查每個節(jié)點的網(wǎng)格索引,并索引場景的mMeshes數(shù)組來獲取對應(yīng)的網(wǎng)格。返回的網(wǎng)格將會傳遞到processMesh函數(shù)中,它會返回一個Mesh類對象,我們可以將他存儲在meshes數(shù)組中。當(dāng)所有網(wǎng)格都被處理后,我們會遍歷節(jié)點的所有子節(jié)點,并對子節(jié)點中的網(wǎng)格傳遞到processMesh函數(shù)中,不斷遞歸下去直到節(jié)點中不再存在子節(jié)點為止。
1.2.3 處理模型網(wǎng)格
網(wǎng)格傳遞到processMesh函數(shù)后,開始對網(wǎng)格進(jìn)行處理。處理網(wǎng)格的過程主要分為兩步:獲取所有的定點數(shù)據(jù);獲取他們的頂點索引。處理后的數(shù)據(jù)將會存儲在兩個vector當(dāng)中,我們會使用他們構(gòu)建一個Mesh類對象,作為processMesh函數(shù)的返回值。
為了獲取頂點數(shù)據(jù),我們首先定義一個Vertex結(jié)構(gòu):
struct Vertex
{
glm::vec3 Position;
glm::vec3 Normal;
};
我們將在每個迭代之后將它加到vector
Assimp的接口定義了每個網(wǎng)格都有一個面(Face)數(shù)組,一個面包含了多個索引,他們定義了在每個圖元中我們應(yīng)該繪制哪個頂點,并以什么順序繪制。因此,我們遍歷了所有的面(使用mesh->mNumFaces來獲?。?,并存儲了面的索引到vector
1.2.4 繪制網(wǎng)格
現(xiàn)在,我們有一大列用于渲染的網(wǎng)格數(shù)據(jù)。將這些數(shù)據(jù)按照OpenGL渲染的標(biāo)準(zhǔn)步驟,配置正確的緩沖,并通過頂點屬性指針定義頂點著色器的布局等,這些設(shè)置都集中在mesh類的成員函數(shù)setupMesh()中。
初始化Model類對象,并調(diào)用其成員函數(shù)Draw(Shader shader),此函數(shù)將遍歷類對象的meshes數(shù)組,并調(diào)用Mesh類的成員函數(shù)Draw(Shader shader),根據(jù)頂點數(shù)組對象所綁定緩沖中的數(shù)據(jù),繪制模型。
2 實驗結(jié)果
根據(jù)前文所述內(nèi)容,在Visual Studio2017平臺實現(xiàn)了對模型文件的讀取、顯示與三維漫游功能。為了驗證系統(tǒng)顯示三維模型的實際效果,選用了CATIA中STL格式的模型文件,下面為得到的三維模型。
3 結(jié)語
對模型文件的讀取與顯示,是對模型一切后續(xù)操作的前提和基礎(chǔ)。本文通過對OpenGL與模型文件的研究,以Visual Studio2017作為開發(fā)平臺,利用Assimp庫讀取模型文件數(shù)據(jù),并通過OpenGL顯示出了模型,今后,可將這種方法應(yīng)用于機(jī)器人仿真軟件開發(fā)、三維視景建模等領(lǐng)域。
【參考文獻(xiàn)】
[1]張代聰.基于OpenGL的交互式PLC虛擬仿真系統(tǒng)[D].山東大學(xué),2012.
[2]Richard S.Wright, Jr.OpenGL超級寶典[M].北京:人民郵電出版社,2012.
[3]肖健,魏雄,王仁波.基于 OpenGL 的大型建筑三維場景模擬的實現(xiàn)與意義[J].電子質(zhì)量,2016(11):88-92.