Commit 4c35d544 authored by Jan Möbius's avatar Jan Möbius

Merge branch 'obj-fix-wrong-indices' into 'master'

Fixed broken indices for some cases of OBJ parsing by using two passes

(Continuing fixing / discussion from https://graphics.rwth-aachen.de:9000/OpenMesh/OpenMesh/merge_requests/51)

This merge request is fixing an issue that came up as a follow-up of the following merge request:
 https://graphics.rwth-aachen.de:9000/OpenMesh/OpenMesh/merge_requests/51

The problem it fixes occurs for some kinds of OBJ data, where vertices and face data are stored interleaved and, at the same time, the mesh contains some non-manifold geometry.  As non-manifold geometry triggers the on-the-fly creation of new vertices during parsing, the indices from the OBJ file do not match any more and the result gets messed up.

The straightforward solution applied on this branch is to parse to whole OBJ file in two passes, first the vertices and then the material data and faces. This way, possible extra vertices will always be added to the back, not interfering with indices from the OBJ file

I tested the performance on a 1.1 GB OBJ file. The loading time on my machine increased from ~59 seconds to ~65 seconds, so I believe the performance overhead could probably be considered acceptable.

Looking forward to your feedback!


See merge request !84
parents 6b8587fc f53429fd
Pipeline #2920 passed with stage
in 22 minutes and 27 seconds
......@@ -279,6 +279,128 @@ read_material(std::fstream& _in)
}
return true;
}
//-----------------------------------------------------------------------------
bool
_OBJReader_::
read_vertices(std::istream& _in, BaseImporter& _bi, Options& _opt,
std::vector<Vec3f> & normals,
std::vector<Vec3f> & colors,
std::vector<Vec3f> & texcoords3d,
std::vector<Vec2f> & texcoords,
std::vector<VertexHandle> & vertexHandles,
Options & fileOptions)
{
float x, y, z, u, v, w;
float r, g, b;
std::string line;
std::string keyWrd;
std::stringstream stream;
// Options supplied by the user
const Options & userOptions = _opt;
while( _in && !_in.eof() )
{
std::getline(_in,line);
if ( _in.bad() ){
omerr() << " Warning! Could not read file properly!\n";
return false;
}
// Trim Both leading and trailing spaces
trimString(line);
// comment
if ( line.size() == 0 || line[0] == '#' || isspace(line[0]) ) {
continue;
}
stream.str(line);
stream.clear();
stream >> keyWrd;
// vertex
if (keyWrd == "v")
{
stream >> x; stream >> y; stream >> z;
if ( !stream.fail() )
{
vertexHandles.push_back(_bi.add_vertex(OpenMesh::Vec3f(x,y,z)));
stream >> r; stream >> g; stream >> b;
if ( !stream.fail() )
{
if ( userOptions.vertex_has_color() ) {
fileOptions += Options::VertexColor;
colors.push_back(OpenMesh::Vec3f(r,g,b));
}
}
}
}
// texture coord
else if (keyWrd == "vt")
{
stream >> u; stream >> v;
if ( !stream.fail() ){
if ( userOptions.vertex_has_texcoord() || userOptions.face_has_texcoord() ) {
texcoords.push_back(OpenMesh::Vec2f(u, v));
// Can be used for both!
fileOptions += Options::VertexTexCoord;
fileOptions += Options::FaceTexCoord;
// try to read the w component as it is optional
stream >> w;
if ( !stream.fail() )
texcoords3d.push_back(OpenMesh::Vec3f(u, v, w));
}
}else{
omerr() << "Only single 2D or 3D texture coordinate per vertex"
<< "allowed!" << std::endl;
return false;
}
}
// color per vertex
else if (keyWrd == "vc")
{
stream >> r; stream >> g; stream >> b;
if ( !stream.fail() ){
if ( userOptions.vertex_has_color() ) {
colors.push_back(OpenMesh::Vec3f(r,g,b));
fileOptions += Options::VertexColor;
}
}
}
// normal
else if (keyWrd == "vn")
{
stream >> x; stream >> y; stream >> z;
if ( !stream.fail() ) {
if (userOptions.vertex_has_normal() ){
normals.push_back(OpenMesh::Vec3f(x,y,z));
fileOptions += Options::VertexNormal;
}
}
}
}
return true;
}
//-----------------------------------------------------------------------------
......@@ -286,19 +408,19 @@ bool
_OBJReader_::
read(std::istream& _in, BaseImporter& _bi, Options& _opt)
{
std::string line;
std::string keyWrd;
float x, y, z, u, v, w;
float r, g, b;
BaseImporter::VHandles vhandles;
std::vector<Vec3f> normals;
std::vector<Vec3f> colors;
std::vector<Vec3f> texcoords3d, face_texcoords3d;
std::vector<Vec2f> texcoords, face_texcoords;
std::vector<Vec3f> texcoords3d;
std::vector<Vec2f> texcoords;
std::vector<VertexHandle> vertexHandles;
BaseImporter::VHandles vhandles;
std::vector<Vec3f> face_texcoords3d;
std::vector<Vec2f> face_texcoords;
std::string matname;
std::stringstream stream, lineData, tmp;
......@@ -310,7 +432,18 @@ read(std::istream& _in, BaseImporter& _bi, Options& _opt)
// Options collected via file parsing
Options fileOptions;
// pass 1: read vertices
if ( !read_vertices(_in, _bi, _opt,
normals, colors, texcoords3d, texcoords,
vertexHandles, fileOptions) ){
return false;
}
// reset stream for second pass
_in.clear();
_in.seekg(0, std::ios::beg);
// pass 2: read vertices
while( _in && !_in.eof() )
{
std::getline(_in,line);
......@@ -351,11 +484,11 @@ read(std::istream& _in, BaseImporter& _bi, Options& _opt)
if ( matStream ){
if ( !read_material( matStream ) )
omerr() << " Warning! Could not read file properly!\n";
omerr() << " Warning! Could not read file properly!\n";
matStream.close();
}else
omerr() << " Warning! Material file '" << matFile << "' not found!\n";
omerr() << " Warning! Material file '" << matFile << "' not found!\n";
//omlog() << " " << materials_.size() << " materials loaded.\n";
......@@ -380,82 +513,7 @@ read(std::istream& _in, BaseImporter& _bi, Options& _opt)
}
}
// vertex
else if (keyWrd == "v")
{
stream >> x; stream >> y; stream >> z;
if ( !stream.fail() )
{
vertexHandles.push_back(_bi.add_vertex(OpenMesh::Vec3f(x,y,z)));
stream >> r; stream >> g; stream >> b;
if ( !stream.fail() )
{
if ( userOptions.vertex_has_color() ) {
fileOptions += Options::VertexColor;
colors.push_back(OpenMesh::Vec3f(r,g,b));
}
}
}
}
// texture coord
else if (keyWrd == "vt")
{
stream >> u; stream >> v;
if ( !stream.fail() ){
if ( userOptions.vertex_has_texcoord() || userOptions.face_has_texcoord() ) {
texcoords.push_back(OpenMesh::Vec2f(u, v));
// Can be used for both!
fileOptions += Options::VertexTexCoord;
fileOptions += Options::FaceTexCoord;
// try to read the w component as it is optional
stream >> w;
if ( !stream.fail() )
texcoords3d.push_back(OpenMesh::Vec3f(u, v, w));
}
}else{
omerr() << "Only single 2D or 3D texture coordinate per vertex"
<< "allowed!" << std::endl;
return false;
}
}
// color per vertex
else if (keyWrd == "vc")
{
stream >> r; stream >> g; stream >> b;
if ( !stream.fail() ){
if ( userOptions.vertex_has_color() ) {
colors.push_back(OpenMesh::Vec3f(r,g,b));
fileOptions += Options::VertexColor;
}
}
}
// normal
else if (keyWrd == "vn")
{
stream >> x; stream >> y; stream >> z;
if ( !stream.fail() ) {
if (userOptions.vertex_has_normal() ){
normals.push_back(OpenMesh::Vec3f(x,y,z));
fileOptions += Options::VertexNormal;
}
}
}
// face
// faces
else if (keyWrd == "f")
{
int component(0), nV(0);
......
......@@ -170,8 +170,17 @@ private:
bool read_material( std::fstream& _in );
private:
bool read_vertices(std::istream& _in, BaseImporter& _bi, Options& _opt,
std::vector<Vec3f> & normals,
std::vector<Vec3f> & colors,
std::vector<Vec3f> & texcoords3d,
std::vector<Vec2f> & texcoords,
std::vector<VertexHandle> & vertexHandles,
Options & fileOptions);
std::string path_;
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment