http://blog.sina.com.cn/s/blog_6db61ebf01017325.html
要顺利读取obj模型文件,先要了解obj文件的格式。OBJ文件格式是非常简单的,它以纯文本的形式存储了模型的顶点、法线和纹理坐标和材质使用信息。
OBJ文件的每行的格式如下:前缀 参数1 参数2 参数3 ...
其中,前缀标识了这一行所存储的信息类型。参数则是具体的数据。
OBJ文件常见的的前缀有:
§
§
§
§
§
§
现在,我们再来看一下OBJ文件的结构。在一个OBJ文件中,首先有一些以v、vt或vn前缀开头的行指定了所有的顶点、纹理坐标、法线的坐标。然后再由一些以f开头的行指定每一个三角形所对应的顶点、纹理坐标和法线的索引。在顶点、纹理坐标和法线的索引之间,使用符号“/”隔开的。
一个f行可以以下面几种格式出现:
§
§
§
§
值得注意的是文件中的索引值是以1作为起点的,这一点与C语言中以0作为起点有很大的不同。在渲染的时候应注意将从文件中读取的坐标值减去1。
由于通常我们拿到的文件中只出现顶点和法线数据,每个面存储顶点和法线索引,所以我们要声明如下几个全局函数:
int v_num=0; //记录点的数量
int vn_num=0;//记录法线的数量
int f_num=0; //记录面的数量
GLfloat **vArr; //存放点的二维数组
GLfloat **vnArr;//存放法线的二维数组
int **fvArr; //存放面顶点的二维数组
int **fnArr; //存放面法线的二维数组
string s1;
GLfloat f2,f3,f4;
为了给存放顶点法线等二维数组分配存储空间,需要知道顶点和法线等的数量,使用下面的函数计算点、法线、面的数量:
void getLineNum(const std::string & sFileName)
{
ifstream infile(sFileName.c_str());
string sline;
v_num=vn_num=f_num=0;
getline(infile,sline);
//while(getline(infile,sline))
while(sline.size()!=0)
{//从指定文件逐行读取
if(sline[0]=='v')
{
if(sline[1]=='n')
vn_num++;
else
v_num++;
}
else if(sline[0]=='f')
f_num++;
getline(infile,sline);
}
infile.close();
}
用下面的函数把文件内容读到上面定义的数组中去
int readfile(string addrstr)
{
vArr=new GLfloat*[v_num];
for (int i=0;i<v_num;i++)
{
}
vnArr=new GLfloat*[vn_num];
for (i=0;i<vn_num;i++)
{
}
fvArr=new int*[f_num];
fnArr=new int*[f_num];
for (i=0;i<f_num;i++)
{
}
ifstream infile(addrstr.c_str());
string sline;//每一行
int ii=0,jj=0,kk=0;
while(getline(infile,sline))
{
if(sline[0]=='v')
{
}
if (sline[0]=='f') //读取面
{
}
return 0;
}
然后在绘制之前,初始化时,调用这两个函数读取模型即可:
getLineNum("cow.obj");
readfile("cow.obj");
相应的绘制代码:
for (int i=0;i<f_num;i++)
{
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_TRIANGLES);
glNormal3f(vnArr[fnArr[i][0]-1][0], vnArr[fnArr[i][0]-1][1],
glVertex3f(vArr[fvArr[i][0]-1][0], vArr[fvArr[i][0]-1][1],
glNormal3f(vnArr[fnArr[i][1]-1][0], vnArr[fnArr[i][1]-1][1],
glVertex3f(vArr[fvArr[i][1]-1][0], vArr[fvArr[i][1]-1][1],
glNormal3f(vnArr[fnArr[i][2]-1][0], vnArr[fnArr[i][2]-1][1],
glVertex3f(vArr[fvArr[i][2]-1][0], vArr[fvArr[i][2]-1][1],
glEnd();
}
如果想读取其他的obj文件,相应的分配一个存储空间,读取相应的数据,然后在绘制时使用这些数据就行了。