vcglib库的入坑体验(读取obj文件并显示)

写在前面:vcglib的坑真的是太深了,慎入!!! 各种文档不全,使用全靠看源码和猜,网上资料很少而且基本都是复制粘贴,有用的信息真的很少!(附上vcglib的文档 真的能看到自闭)

本文使用vcglib库进行读取obj文件(其他各种3d模型格式也是同样的方法)并显示,但是目前仍然遇到一些问题没有解决:读取的纹理信息全部缺失(读出来全部为0,因此下图并没有贴纹理),查了很久真心不知道为什么,如果有哪位大佬偶尔看到本文,劳烦告知如何解决。

vcglib库的入坑体验(读取obj文件并显示)_第1张图片

一、安装vcglib库

vcglib的安装非常简单

  1. 下载源码

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

  2. 解压得到下面六个文件夹
    vcglib库的入坑体验(读取obj文件并显示)_第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   ::AsVertexType,
        vcg::Use     ::AsEdgeType,
        vcg::Use     ::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, std::vector > {};

2. 读取obj文件

MyMesh m_obj;  //定义一个网格对象
int mask;     //定义mask
//注意your filePath不能有中文路径
vcg::tri::io::ImporterOBJ::Open(m_obj, "your filePath",mask);
//为每个点计算法线并归一化
vcg::tri::RequirePerVertexNormal(m_obj);
vcg::tri::UpdateNormal::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& vs = m_obj.vert;
vector& es = m_obj.edge;
vector& 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& 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& fs = m_obj.face;
    glVertexPointer(3,GL_DOUBLE,0,vertex);
    glNormalPointer(GL_DOUBLE,0,normal);
    glDrawArrays(GL_TRIANGLES,0,fs.size()*3);

}

经过以上步骤即可完成obj的读取和绘制,虽然整理之后的过程比较简单,但是在搜索资料的过程真的很痛苦, 有一个好的说明文档真的很重要!!!

几个vcg库的例子,记录一下

你可能感兴趣的:(C++,图形学)