Commit f377c86a authored by Jan Möbius's avatar Jan Möbius

Merge branch 'fixOBJWriterMissingTexcoords' into 'master'

added code to write faceTexCoords to obj writer.

fixes #25 
* Added accessor functions for HalfEdgeHandles and faceTexCoords to base exporter and exporter template.
* Added functionality to store FaceTexCoords to objwriter
* Added unittest to write and read faceTexcoords with a test obj file

See merge request !73
parents 6f9589dc 80192d94
Pipeline #3397 passed with stage
in 53 minutes and 16 seconds
......@@ -103,12 +103,23 @@ public:
virtual Vec3f colorf(VertexHandle _vh) const = 0;
virtual Vec4f colorAf(VertexHandle _vh) const = 0;
virtual Vec2f texcoord(VertexHandle _vh) const = 0;
virtual Vec2f texcoord(HalfedgeHandle _heh) const = 0;
// get face data
virtual unsigned int
get_vhandles(FaceHandle _fh,
std::vector<VertexHandle>& _vhandles) const=0;
///
/// \brief getHeh returns the HalfEdgeHandle that belongs to the face
/// specified by _fh and has a toVertexHandle that corresponds to _vh.
/// \param _fh FaceHandle that is used to search for the half edge handle
/// \param _vh to_vertex_handle of the searched heh
/// \return HalfEdgeHandle or invalid HalfEdgeHandle if none is found.
///
virtual HalfedgeHandle getHeh(FaceHandle _fh, VertexHandle _vh) const = 0;
virtual unsigned int
get_face_texcoords(std::vector<Vec2f>& _hehandles) const = 0;
virtual Vec3f normal(FaceHandle _fh) const = 0;
virtual Vec3uc color (FaceHandle _fh) const = 0;
virtual Vec4uc colorA(FaceHandle _fh) const = 0;
......
......@@ -164,6 +164,13 @@ public:
#endif
}
Vec2f texcoord(HalfedgeHandle _heh) const
{
return (mesh_.has_halfedge_texcoords2D()
? vector_cast<Vec2f>(mesh_.texcoord2D(_heh))
: Vec2f(0.0f, 0.0f));
}
// get edge data
Vec3uc color(EdgeHandle _eh) const
......@@ -223,6 +230,31 @@ public:
return count;
}
unsigned int get_face_texcoords(std::vector<Vec2f>& _hehandles) const
{
unsigned int count(0);
_hehandles.clear();
for(typename Mesh::CHIter he_it=mesh_.halfedges_begin();
he_it != mesh_.halfedges_end(); ++he_it)
{
_hehandles.push_back(vector_cast<Vec2f>(mesh_.texcoord2D( *he_it)));
++count;
}
return count;
}
HalfedgeHandle getHeh(FaceHandle _fh, VertexHandle _vh) const
{
typename Mesh::ConstFaceHalfedgeIter fh_it;
for(fh_it = mesh_.cfh_iter(_fh); fh_it.is_valid();++fh_it)
{
if(mesh_.to_vertex_handle(*fh_it) == _vh)
return *fh_it;
}
return *fh_it;
}
Vec3f normal(FaceHandle _fh) const
{
return (mesh_.has_face_normals()
......
......@@ -257,6 +257,42 @@ write(std::ostream& _out, BaseExporter& _be, Options _opt, std::streamsize _prec
if (useMatrial && _opt.check(Options::FaceColor) )
_out << "mtllib " << objName_ << ".mat" << '\n';
std::map<Vec2f,int> texMap;
//collect Texturevertices from halfedges
if(_opt.check(Options::FaceTexCoord))
{
std::vector<Vec2f> texCoords;
//add all texCoords to map
unsigned int num = _be.get_face_texcoords(texCoords);
for(unsigned int i = 0; i < num ; ++i)
{
texMap[texCoords[i]] = i;
}
}
//collect Texturevertices from vertices
if(_opt.check(Options::VertexTexCoord))
{
for (int i=0, nF=_be.n_faces(); i<nF; ++i)
{
vh = VertexHandle(int(i));
t = _be.texcoord(vh);
texMap[t] = i;
}
}
// assign each texcoord in the map its id
// and write the vt entries
if(_opt.check(Options::VertexTexCoord) || _opt.check(Options::FaceTexCoord))
{
int texCount = 0;
for(std::map<Vec2f,int>::iterator it = texMap.begin(); it != texMap.end() ; ++it)
{
_out << "vt " << it->first[0] << " " << it->first[1] << '\n';
it->second = ++texCount;
}
}
// vertex data (point, normals, texcoords)
for (i=0, nV=_be.n_vertices(); i<nV; ++i)
{
......@@ -268,17 +304,15 @@ write(std::ostream& _out, BaseExporter& _be, Options _opt, std::streamsize _prec
_out << "v " << v[0] <<" "<< v[1] <<" "<< v[2] << '\n';
if (_opt.check(Options::VertexNormal))
_out << "vn " << n[0] <<" "<< n[1] <<" "<< n[2] << '\n';
if (_opt.check(Options::VertexTexCoord))
_out << "vt " << t[0] <<" "<< t[1] << '\n';
_out << "vn " << n[0] <<" "<< n[1] <<" "<< n[2] << '\n';
}
size_t lastMat = std::numeric_limits<std::size_t>::max();
// we do not want to write seperators if we only write vertex indices
bool onlyVertices = !_opt.check(Options::VertexTexCoord)
&& !_opt.check(Options::VertexNormal);
&& !_opt.check(Options::VertexNormal)
&& !_opt.check(Options::FaceTexCoord);
// faces (indices starting at 1 not 0)
for (i=0, nF=_be.n_faces(); i<nF; ++i)
......@@ -319,9 +353,18 @@ write(std::ostream& _out, BaseExporter& _be, Options _opt, std::streamsize _prec
// write separator
_out << "/" ;
// write vertex texture coordinate index
if (_opt.check(Options::VertexTexCoord))
_out << idx;
//write texCoords index from halfedge
if(_opt.check(Options::FaceTexCoord))
{
_out << texMap[_be.texcoord(_be.getHeh(FaceHandle(int(i)),vhandles[j]))];
}
else
{
// write vertex texture coordinate index
if (_opt.check(Options::VertexTexCoord))
_out << texMap[_be.texcoord(vh)];
}
// write vertex normal index
if ( _opt.check(Options::VertexNormal) ) {
......
......@@ -202,6 +202,62 @@ TEST_F(OpenMeshReadWriteOBJ, LoadSimpleOBJCheckTexCoords) {
mesh_.release_halfedge_texcoords2D();
}
/*
* Just load and store obj file of a cube and checks the halfedge texCoords
*/
TEST_F(OpenMeshReadWriteOBJ, LoadStoreSimpleOBJCheckTexCoords) {
mesh_.clear();
mesh_.request_halfedge_texcoords2D();
OpenMesh::IO::Options options;
options += OpenMesh::IO::Options::FaceTexCoord;
std::string file_name = "cube-minimal-texCoords.obj";
bool ok = OpenMesh::IO::read_mesh(mesh_, file_name,options);
EXPECT_TRUE(ok) << file_name;
options.clear();
options += OpenMesh::IO::Options::FaceTexCoord;
bool writeOk = OpenMesh::IO::write_mesh(mesh_,"writeTest.obj",options);
EXPECT_TRUE(writeOk) << "writeTest.obj";
mesh_.release_halfedge_texcoords2D();
Mesh loadedMesh_;
loadedMesh_.clear();
loadedMesh_.request_halfedge_texcoords2D();
options.clear();
options += OpenMesh::IO::Options::FaceTexCoord;
bool readOk = OpenMesh::IO::read_mesh(loadedMesh_, "writeTest.obj",options);
EXPECT_TRUE(readOk) << file_name;
EXPECT_EQ(1, loadedMesh_.texcoord2D(mesh_.halfedge_handle(0))[0] ) << "Wrong texCoord at halfedge 0 component 0";
EXPECT_EQ(1, loadedMesh_.texcoord2D(mesh_.halfedge_handle(0))[1] ) << "Wrong texCoord at halfedge 0 component 1";
EXPECT_EQ(3, loadedMesh_.texcoord2D(mesh_.halfedge_handle(10))[0] ) << "Wrong texCoord at halfedge 1 component 0";
EXPECT_EQ(3, loadedMesh_.texcoord2D(mesh_.halfedge_handle(10))[1] ) << "Wrong texCoord at halfedge 1 component 1";
EXPECT_EQ(6, loadedMesh_.texcoord2D(mesh_.halfedge_handle(19))[0] ) << "Wrong texCoord at halfedge 4 component 0";
EXPECT_EQ(6, loadedMesh_.texcoord2D(mesh_.halfedge_handle(19))[1] ) << "Wrong texCoord at halfedge 4 component 1";
EXPECT_EQ(7, loadedMesh_.texcoord2D(mesh_.halfedge_handle(24))[0] ) << "Wrong texCoord at halfedge 7 component 0";
EXPECT_EQ(7, loadedMesh_.texcoord2D(mesh_.halfedge_handle(24))[1] ) << "Wrong texCoord at halfedge 7 component 1";
EXPECT_EQ(9, loadedMesh_.texcoord2D(mesh_.halfedge_handle(30))[0] ) << "Wrong texCoord at halfedge 9 component 0";
EXPECT_EQ(9, loadedMesh_.texcoord2D(mesh_.halfedge_handle(30))[1] ) << "Wrong texCoord at halfedge 9 component 1";
EXPECT_EQ(12, loadedMesh_.texcoord2D(mesh_.halfedge_handle(35))[0] ) << "Wrong texCoord at halfedge 11 component 0";
EXPECT_EQ(12, loadedMesh_.texcoord2D(mesh_.halfedge_handle(35))[1] ) << "Wrong texCoord at halfedge 11 component 1";
loadedMesh_.release_halfedge_texcoords2D();
}
/*
* Just load a obj file of a cube and checks the 3d halfedge texCoords
*/
......
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