通常来说我们构建一个模型是比较复杂的工作,那么我们还有什么途径获得模型呢。其中一种方法就是导入obj模型,不要被这个名词给吓到了,其实就是把一个制作好的模型保存到一个文件中,我们称为obj文件。
先上图片:
下面说明如何读取单个obj文件:
我们先了解一下obj文件里都是表示什么
v 表示点的坐标值
vt表示纹理贴图坐标值
vn表示点的法线
f 表示的是面,本例中针对的是三角形的面
f 后面的参数也是三个,表示为: 点索引/纹理索引/法线索引
1.首先定义一些数据结构:
struct Face
{int v[3];int t[3];int n[3];
};QVector<QVector3D> m_vertexs;//保存点坐标QVector<QVector3D> m_normals;//保存法线坐标QVector<QVector3D> m_texcoords;//保存纹理坐标
2.读取模型的代码实现:
void Mesh::loadMeshFrom(QString filename)
{m_vertexs.clear();m_texcoords.clear();m_normals.clear();QFile file(filename);if(!file.open(QIODevice::ReadOnly)){qDebug()<<"[Error] fail to open file :"<<filename;return;}QTextStream ts(&file);// Temp arrays;QVector<QVector3D> v;QVector<QVector3D> vn;QVector<QVector3D> vt;QVector<QStringList> str_faces;QVector<Face> faces;while(!ts.atEnd()){QStringList list = ts.readLine().split(QRegExp("(\\s+)"));list.removeAll(" ");if(list.size() == 0 )break;if(list[0] == "v")v.push_back(QVector3D(list[1].toFloat(),list[2].toFloat(),list[3].toFloat()));if(list[0] == "vn")vn.push_back(QVector3D(list[1].toFloat(),list[2].toFloat(),list[3].toFloat()));if(list[0] == "vt")vt.push_back(QVector3D(list[1].toFloat(),list[2].toFloat(),0));if(list[0] == "f")str_faces.push_back(list);}for( int i =0; i< str_faces.size(); i++){Face face;for( int j = 1; j<=3; j++){QStringList list = str_faces[i][j].split("/");face.v[j-1] = list[0].toInt() -1;face.t[j-1] = list[1].toInt() -1;face.n[j-1] = list[2].toInt() -1;tmp[list[0].toInt()-1].push_back(faces.size());//放入面的索引}faces.push_back(face);}for( int i = 0; i<faces.size();i++){for( int k = 0; k < 3;k++){m_vertexs.push_back( v[faces[i].v[k]]);//把每一个面从索引转换为具体坐标m_normals.push_back( vn[faces[i].n[k]]);m_texcoords.push_back(vt[faces[i].t[k]]);}}file.close();
}
从obj模型中读取完模型数据之后我们需要渲染这个模型:
3.如果我们用顶点数组的话我们要把上面数据转成数组保存,如:
GLdouble *vertex;
for(int i= 0; i< m_vertex.size();i++){vertex[i*3+0] = m_vertex[i].x();vertex[i*3+1] = m_vertex[i].y();vertex[i*3+2] = m_vertex[i].z();}
法线和纹理坐标同理
4.使用顶点数组渲染
void renderObj()
{glEnableClientState(GL_VERTEX_ARRAY);glEnableClientState(GL_TEXTURE_COORD_ARRAY);glEnableClientState(GL_NORMAL_ARRAY);glPushMatrix();glTexCoordPointer(2,GL_DOUBLE,0,texcood);glNormalPointer(GL_DOUBLE,0,normal);glVertexPointer(3,GL_DOUBLE,0,vertex);glDrawArrays(GL_TRIANGLES,0,m_vertex.size());glPopMatrix();glFlush();
}
这样我们就能绘制出不带纹理的模型了,当然你也可以手动添加纹理,但是这样做是很费力的。



















