Qt实现读取显示obj文件——读取数据

来源:互联网 发布:mac版bt下载软件 编辑:程序博客网 时间:2024/04/30 16:25

前一篇写了关于实现的一些说明Qt实现读取显示obj文件——说明,这一篇说一说数据的读取~


说明

在头文件中我们建立一个OBJ文件的数据模型类;记录一些模型的结构与之后可能会使用的数据结构;(之后会在Github上上传所有的源码,但是数据不会上传~)

class _GLModel{public:    QString path;//obj文件路径    QString mtllibName;//材质文件名称    size_t num_Vertices;//节点个数    size_t num_Normals;//节点向量的个数    size_t num_Textcoords;//节点纹理坐标个数    size_t num_Materials;//材质个数    size_t num_Faces;//面的个数    QList<Point3> list_Vertices;//节点对象集合    QList<VertNormals> list_Normals;//节点向量集合    QList<TextCoords> list_Textcoords;//纹理坐标集合    QList<Face> list_Faces;//面集合    QList<Material> list_Materials;//材质集合    QList<FacetNormal> list_FaceNormal;//面向量集合    QList<QString> list_ImagePath;//贴图路径集合,全路径    //GLfloat Center[3];//进行归一化之后的坐标中心    int textureArray[MAX_TEXTURE];//注册纹理数组};

读取OBJ数据结构

读取数据使用的是Qt中的类QInfo类,还是挺好用的~就是需要的注意的是每一行的结尾都会有\r\n回车换行符,和中文乱码,需要注意乱码和使用Trimmed()方法处理:

//读取OBJ文件_GLModel* _glReadOBJ(QString filename){    QFile file(filename);    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {        return NULL;    }    QString dirPath = _glGetDir(filename); QStringList list; QString currentMaterialName;    _GLModel* model;    model = new _GLModel();    QString split = ' ';    model->path = filename;    model->num_Faces = 0;    model->num_Materials = 0;    model->num_Normals = 0;    model->num_Textcoords = 0;    model->num_Vertices = 0;    Point3 *v;    TextCoords *vt;    VertNormals *vn;    Face *f;    while (!file.atEnd()) {        QByteArray line = file.readLine();        QString str(line);        if (str.length() < 2)//太短~            continue;        if (str[0] == 'm')        {            QStringList str0 = str.split(' ');            QString mtlname = str0[1];            mtlname = mtlname.trimmed();//一定要trimmed处理,否则路径有问题            dirPath.append(mtlname);            model->mtllibName = dirPath;            _glReadMTL(model, model->mtllibName);        }        else if (str[0] == 'v'){            if (str[1] == 't'){//纹理                list = str.split(split);//无论是否包括Z方向的纹理都先取前两个值                vt = new TextCoords();                vt->U = list[_Y].toFloat(); vt->V = list[_Z].toFloat();                model->num_Textcoords++;                model->list_Textcoords.push_back(*vt);            }            else if (str[1] == 'n'){//法向量                list = str.split(split);                vn = new VertNormals();                vn->_NX = list[_Y].toFloat(); vn->_NY = list[_Z].toFloat(); vn->_NZ = list[_W].toFloat();                model->num_Normals++;                model->list_Normals.push_back(*vn);            }            else//节点~            {                list = str.split(split);                v = new Point3();                v->_X = list[_Y].toFloat(); v->_Y = list[_Z].toFloat(); v->_Z = list[_W].toFloat();                model->num_Vertices++;                model->list_Vertices.push_back(*v);            }        }        else if (str[0] == 'u')//材质的名称        {            list = str.split(split);            currentMaterialName = list[1];        }        else if (str[0] == 'f')//面        {            str = str.trimmed();            list = str.split(split);            f = new Face();            f->materialName = currentMaterialName;            if (list[1].contains('/'))            {                for (int i = 1; i < list.length(); i++)                {                    QStringList sublist = list[i].split('/');                    f->list_index_Points.push_back(sublist[_X].toInt() - 1);                    f->list_index_TextCoords.push_back(sublist[_Y].toInt() - 1);                    if (list[1].split('/').length() == 3)//只有v和vt                    {                        f->list_index_VertNormals.push_back(sublist[_Z].toInt() - 1);                    }                }            }            else//不包括/,那么只有节点            {                for (int i = 1; i < list.length(); i++)                {                    f->list_index_Points.push_back(list[i].toInt() - 1);                }            }            model->num_Faces++;            model->list_Faces.push_back(*f);        }    }    return model;}

读取纹理文件

在读取OBJ的同时还读取了纹理文件mtl:

//读取mtl文件void _glReadMTL(_GLModel *model, QString fileName){    QFile file(fileName);    if (!file.open(QIODevice::ReadOnly)) {        qDebug("mtl文件打开失败。");        return;    }    QString dirPath;    Material *material = NULL; QStringList list;    int index = -1;//材质索引    QString split = ' ';    while (!file.atEnd())    {        QByteArray line = file.readLine();        if (line.length() == 2 && line.at(line.length() - 2) == '\r'&&line.at(line.length() - 1) == '\n')//如果读到了空行且材质指针不为空,那么证明当前的材质已经读完        {            if (material&&material->materialName != NULL)                model->list_Materials.push_back(*material);        }        QString str(line);        if (str[0] == 'n')//名称        {            list = str.split(split);            material = new Material();            material->_Ka[_X] = 0.0; material->_Ka[_Y] = 0.0; material->_Ka[_Z] = 0.0;            material->_Kd[_X] = 0.0; material->_Kd[_Y] = 0.0; material->_Kd[_Z] = 0.0;            material->_Ks[_X] = 0.0; material->_Ks[_Y] = 0.0; material->_Ks[_Z] = 0.0;            QString str1 = list[1];            material->materialName = str1.trimmed();            material->index_Material = ++index;            model->num_Materials++;        }        else if (str[0] == 'm')//贴图路径        {            list = str.split(split);            dirPath = _glGetDir(fileName);//获取文件夹路径            dirPath.append(list[1].trimmed());            material->imageName = dirPath;            model->list_ImagePath.push_back(dirPath);        }        else if (str[0] == 'K')        {            list = str.split(split);            if (str[1] == 'a')            {                material->_Ka[0] = list[1].toFloat();                material->_Ka[1] = list[2].toFloat();                material->_Ka[2] = list[3].toFloat();            }            else if (str[1] == 'd')            {                material->_Kd[0] = list[1].toFloat();                material->_Kd[1] = list[2].toFloat();                material->_Kd[2] = list[3].toFloat();            }            else if (str[1] == 's')            {                material->_Ks[0] = list[1].toFloat();                material->_Ks[1] = list[2].toFloat();                material->_Ks[2] = list[3].toFloat();            }        }    }}

在实际的绘制obj中我虽然读取了材质参数,但是实际上并没有运用这些参数,主要用到了材质的纹理路径;我的意图主要还是渲染数据并贴上纹理~有兴趣的同学可以参考glm.c去自己实现,其实也很简单~

0 0
原创粉丝点击