前言
istringstream的用法
这里需要补充的知识点是
istringstream.ignore(256, ' ');
Obj模型的结构
在一个OBJ文件中:
以v前缀开头的行
| 指定了所有的顶点
|
以vt前缀开头的行
| 指定了所有的纹理坐标
|
以vn前缀开头的行
| 指定了所有的法线坐标
|
以f前缀开头的行
| 指定每一个三角形所对应的顶点、纹理坐标和法线的索引。在顶点、纹理坐标和法线的索引之间,使用符号“/”隔开的。
|
一个f行可以以下面几种格式出现:
f 1 2 3
| 表示以第1、2、3号顶点组成一个三角形
|
f 1/3 2/5 3/4
| 表示以第1、2、3号顶点组成一个三角形,其中第一个顶点的纹理坐标的索引值为3,第二个顶点的纹理坐标的索引值为5,第三个顶点的纹理坐标的索引值为4
|
f 1/3/4 2/5/6 3/4/2
| 表示以第1、2、3号顶点组成一个三角形,其中第一个顶点的纹理坐标的索引值为3,其法线的索引值是4;第二个顶点的纹理坐标的索引值为5,其法线的索引值是6;第三个顶点的纹理坐标的索引值为6,其法线的索引值是2
|
f 1//4 2//6 3//2
| 表示以第1、2、3号顶点组成一个三角形,且忽略纹理坐标。其中第一个顶点的法线的索引值是4;第二个顶点的法线的索引值是6;第三个顶点的法线的索引值是2
|
注意:文件中的索引值是以1作为起点的,在渲染的时候应注意将从文件中读取的坐标值减去1。
代码
Void ReadOBJ(const std::string& strObjPath, std::vector<CGAL::Simple_cartesian<double>::Point_3>& points, std::vector<CGAL::Simple_cartesian<double>::Point_2>& uvs,std::vector<std::vector<std::size_t> >& ptfaces)
{
std::ifstream input(strObjPath);
std::string line;
CGAL::Simple_cartesian<double>::Point_3 p_3;
CGAL::Simple_cartesian<double>::Point_2 p_2;
while (getline(input, line))
{
if (line[0] == 'v' && line[1] == ' ')
{
//顶点坐标
std::istringstream iss(line.substr(1));
iss >> p_3;
if (!iss)
{
return false;
}
points.push_back(p_3);
}
else if (line[0] == 'v' && line[1] == 't' && line[2] == ' ')
{
//UV坐标
std::istringstream iss(line.substr(2));
iss >> p_2;
if (!iss)
{
return false;
}
uvs.push_back(p_2);
}
else if (line[0] == 'f' && line[1] == ' ')
{
//顶点三角面片
std::istringstream ptiss(line.substr(1));
int i;
ptfaces.push_back(std::vector<std::size_t>());
while (ptiss >> i)
{
ptfaces.back().push_back(i-1);
ptiss.ignore(256, ' ');
}
}
}
}