vcglib庫的入坑體驗(讀取obj文件並顯示)

寫在前面:vcglib的坑真的是太深了,慎入!!! 各種文檔不全,使用全靠看源碼和猜,網上資料很少而且基本都是複製粘貼,有用的信息真的很少!(附上vcglib的文檔 真的能看到自閉)

本文使用vcglib庫進行讀取obj文件(其他各種3d模型格式也是同樣的方法)並顯示,但是目前仍然遇到一些問題沒有解決:讀取的紋理信息全部缺失(讀出來全部爲0,因此下圖並沒有貼紋理),查了很久真心不知道爲什麼,如果有哪位大佬偶爾看到本文,勞煩告知如何解決。

讀取的obj文件

一、安裝vcglib庫

vcglib的安裝非常簡單

  1. 下載源碼

    下載地址:https://github.com/cnr-isti-vclab/vcglib/

  2. 解壓得到下面六個文件夾
    在這裏插入圖片描述
    然後將vcg、wrap、eigenlib文件夾添加到編譯器的include文件夾中。

    如果是使用qt則include的路徑爲
    xx:\Qt\Qt5.6.1\5.6\mingw49_32\include

  3. 文件夾的解釋(轉自博客https://www.cnblogs.com/icmzn/p/6640752.html)

    vcg:這是整個庫的核心,其中定義了所有的算法和數據結構。該部分所有的C++代碼都是STL支持的普通數據結構和算法,不包含任何其它標準庫之外的庫,而且可以發現,該部分只包含頭文件(.h)*

    **wrap:**這裏包含一些針對特定需求/上下文/庫的VCG概念的封裝。例如,所有的用於計算機硬盤上很多格式的網格數據的導入和導出;用OpenGL渲染三角形網格的代碼;普通GUI工具如跟蹤球,等等;

    **apps:**這個文件夾包含一些用VCG Lib開發的命令行程序應用。很多例子都能在MeshLab中找到,apps/simple文件夾包含了這些程序的一個基礎的子集,是一個初學者很好的入口點;
    **docs:**文檔(包括這個教程)

    eigenLib:線性代數的eigen庫最近的穩定版本的一個副本(相當於就是借用第三方庫了),VCGLib中的高級矩陣操作都是基於這個庫的。

二、 vcglib的使用

1. 定義數據類型

下面是定義了點、線、面和網格的數據類型,直接添加在代碼中即可,如需要進一步瞭解可以看下這個博文

class MyVertex; class MyEdge; class MyFace;
struct MyUsedTypes : public vcg::UsedTypes<vcg::Use<MyVertex>   ::AsVertexType,
        vcg::Use<MyEdge>     ::AsEdgeType,
        vcg::Use<MyFace>     ::AsFaceType>{};
//存儲點,法向量,紋理座標
class MyVertex : public vcg::Vertex< MyUsedTypes, vcg::vertex::Coord3f,vcg::vertex::TexCoord2f,  vcg::vertex::Normal3f, vcg::vertex::BitFlags  >{};
class MyFace : public vcg::Face<   MyUsedTypes, vcg::face::FFAdj, vcg::face::VFAdj,vcg::face::VertexRef, vcg::face::BitFlags > {};
class MyEdge : public vcg::Edge<   MyUsedTypes> {};
class MyMesh : public vcg::tri::TriMesh<std::vector<MyVertex>, std::vector<MyFace>, std::vector<MyEdge> > {};

2. 讀取obj文件

MyMesh m_obj;  //定義一個網格對象
int mask;     //定義mask
//注意your filePath不能有中文路徑
vcg::tri::io::ImporterOBJ<MyMesh>::Open(m_obj, "your filePath",mask);
//爲每個點計算法線並歸一化
vcg::tri::RequirePerVertexNormal(m_obj);
vcg::tri::UpdateNormal<MyMesh>::PerVertexNormalized(m_obj);

其他類型的文件也是同樣的操作,只是將語句
vcg::tri::io::ImporterOBJ::Open(m_obj, “your filePath”,mask);變成vcg::tri::io::ImporterXXX::Open(m_obj, “your filePath”,mask);
XXX爲你所使用的數據類型,具體支持的類型可以在\wrap\io_trimesh目錄下看到
上面幾句話已經將obj模型讀進m_obj對象中了,下面就是重點了,如何從m_obj中獲取數據

vector<MyVertex>& vs = m_obj.vert;
vector<MyEdge>& es = m_obj.edge;
vector<MyFace>& fs = m_obj.face;

給幾個例子說明一下數據如何取出

MyVertex v = vs[0];   //取第一個點
//v.P()儲存了點的位置座標,v.N()儲存了點的法線座標,v.T()儲存了點的紋理座標

v.P().X() v.P().Y()  v.P().Z()  //取第一個點的XYZ座標
v.N().X() v.N().Y()  v.N().Z()  //取第一個點法線的XYZ座標
v.T().U() v.T().V()             //取第一個點的紋理UV座標    

3. 在opengl中使用數據

下面爲將數據保存到頂點數組中的具體操作

	 vector<MyFace>& fs = m_obj.face;    //取出所有面
	 vertex = new GLdouble[fs.size()*3*3];// 數據類型GLdouble *vertex;
    
     normal  = new GLdouble[fs.size()*3*3];// 數據類型GLdouble *normal;
     int v_index = 0;
     //遍歷所有面
     for(auto fi = m_obj.face.begin(); fi!=m_obj.face.end(); ++fi )
       {
         for( int j =0; j<3 ; j++){
            MyVertex* v= fi->V(j);

            if(fi == m_obj.face.begin())
                qDebug()<< v->T().u();
            normal[v_index] = v->N().X();
            vertex[v_index++] = v->P().X();
            normal[v_index] = v->N().Y();
            vertex[v_index++] = v->P().Y();
            normal[v_index] = v->N().Z();
            vertex[v_index++] = v->P().Z();
         }

     }

最後在opengl中繪製即可

void Widget::renderObj()
{
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);

    vector<MyFace>& fs = m_obj.face;
    glVertexPointer(3,GL_DOUBLE,0,vertex);
    glNormalPointer(GL_DOUBLE,0,normal);
    glDrawArrays(GL_TRIANGLES,0,fs.size()*3);

}

經過以上步驟即可完成obj的讀取和繪製,雖然整理之後的過程比較簡單,但是在搜索資料的過程真的很痛苦, 有一個好的說明文檔真的很重要!!!

幾個vcg庫的例子,記錄一下

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