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
This commit is contained in:
@@ -103,12 +103,23 @@ public:
|
|||||||
virtual Vec3f colorf(VertexHandle _vh) const = 0;
|
virtual Vec3f colorf(VertexHandle _vh) const = 0;
|
||||||
virtual Vec4f colorAf(VertexHandle _vh) const = 0;
|
virtual Vec4f colorAf(VertexHandle _vh) const = 0;
|
||||||
virtual Vec2f texcoord(VertexHandle _vh) const = 0;
|
virtual Vec2f texcoord(VertexHandle _vh) const = 0;
|
||||||
|
virtual Vec2f texcoord(HalfedgeHandle _heh) const = 0;
|
||||||
|
|
||||||
|
|
||||||
// get face data
|
// get face data
|
||||||
virtual unsigned int
|
virtual unsigned int
|
||||||
get_vhandles(FaceHandle _fh,
|
get_vhandles(FaceHandle _fh,
|
||||||
std::vector<VertexHandle>& _vhandles) const=0;
|
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 Vec3f normal(FaceHandle _fh) const = 0;
|
||||||
virtual Vec3uc color (FaceHandle _fh) const = 0;
|
virtual Vec3uc color (FaceHandle _fh) const = 0;
|
||||||
virtual Vec4uc colorA(FaceHandle _fh) const = 0;
|
virtual Vec4uc colorA(FaceHandle _fh) const = 0;
|
||||||
|
|||||||
@@ -164,6 +164,13 @@ public:
|
|||||||
#endif
|
#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
|
// get edge data
|
||||||
|
|
||||||
Vec3uc color(EdgeHandle _eh) const
|
Vec3uc color(EdgeHandle _eh) const
|
||||||
@@ -223,6 +230,31 @@ public:
|
|||||||
return count;
|
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
|
Vec3f normal(FaceHandle _fh) const
|
||||||
{
|
{
|
||||||
return (mesh_.has_face_normals()
|
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) )
|
if (useMatrial && _opt.check(Options::FaceColor) )
|
||||||
_out << "mtllib " << objName_ << ".mat" << '\n';
|
_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)
|
// vertex data (point, normals, texcoords)
|
||||||
for (i=0, nV=_be.n_vertices(); i<nV; ++i)
|
for (i=0, nV=_be.n_vertices(); i<nV; ++i)
|
||||||
{
|
{
|
||||||
@@ -269,16 +305,14 @@ write(std::ostream& _out, BaseExporter& _be, Options _opt, std::streamsize _prec
|
|||||||
|
|
||||||
if (_opt.check(Options::VertexNormal))
|
if (_opt.check(Options::VertexNormal))
|
||||||
_out << "vn " << n[0] <<" "<< n[1] <<" "<< n[2] << '\n';
|
_out << "vn " << n[0] <<" "<< n[1] <<" "<< n[2] << '\n';
|
||||||
|
|
||||||
if (_opt.check(Options::VertexTexCoord))
|
|
||||||
_out << "vt " << t[0] <<" "<< t[1] << '\n';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t lastMat = std::numeric_limits<std::size_t>::max();
|
size_t lastMat = std::numeric_limits<std::size_t>::max();
|
||||||
|
|
||||||
// we do not want to write seperators if we only write vertex indices
|
// we do not want to write seperators if we only write vertex indices
|
||||||
bool onlyVertices = !_opt.check(Options::VertexTexCoord)
|
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)
|
// faces (indices starting at 1 not 0)
|
||||||
for (i=0, nF=_be.n_faces(); i<nF; ++i)
|
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
|
// write separator
|
||||||
_out << "/" ;
|
_out << "/" ;
|
||||||
|
|
||||||
// write vertex texture coordinate index
|
//write texCoords index from halfedge
|
||||||
if (_opt.check(Options::VertexTexCoord))
|
if(_opt.check(Options::FaceTexCoord))
|
||||||
_out << idx;
|
{
|
||||||
|
_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
|
// write vertex normal index
|
||||||
if ( _opt.check(Options::VertexNormal) ) {
|
if ( _opt.check(Options::VertexNormal) ) {
|
||||||
|
|||||||
@@ -202,6 +202,62 @@ TEST_F(OpenMeshReadWriteOBJ, LoadSimpleOBJCheckTexCoords) {
|
|||||||
mesh_.release_halfedge_texcoords2D();
|
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
|
* Just load a obj file of a cube and checks the 3d halfedge texCoords
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user