From b77188e35c06593c8defb9d8422c64f0fb463dc1 Mon Sep 17 00:00:00 2001 From: Jean-Samuel Reynaud Date: Wed, 8 Feb 2017 17:09:26 +0100 Subject: [PATCH] Adding Normals in OBJ exports --- src/Mod/Mesh/App/Core/MeshIO.cpp | 104 ++++++++++++++++++------------- 1 file changed, 61 insertions(+), 43 deletions(-) diff --git a/src/Mod/Mesh/App/Core/MeshIO.cpp b/src/Mod/Mesh/App/Core/MeshIO.cpp index 659af2ac3d3d..fe41d815c1cf 100644 --- a/src/Mod/Mesh/App/Core/MeshIO.cpp +++ b/src/Mod/Mesh/App/Core/MeshIO.cpp @@ -211,7 +211,7 @@ bool MeshInput::LoadFormat(std::istream &str, MeshIO::Format fmt) } } -/** Loads an STL file either in binary or ASCII format. +/** Loads an STL file either in binary or ASCII format. * Therefore the file header gets checked to decide if the file is binary or not. */ bool MeshInput::LoadSTL (std::istream &rstrIn) @@ -800,22 +800,22 @@ bool MeshInput::LoadPLY (std::istream &inp) // check if valid 3d points Property property; - std::size_t num_x = std::count_if(vertex_props.begin(), vertex_props.end(), + std::size_t num_x = std::count_if(vertex_props.begin(), vertex_props.end(), std::bind2nd(property, "x")); if (num_x != 1) return false; - std::size_t num_y = std::count_if(vertex_props.begin(), vertex_props.end(), + std::size_t num_y = std::count_if(vertex_props.begin(), vertex_props.end(), std::bind2nd(property, "y")); if (num_y != 1) return false; - std::size_t num_z = std::count_if(vertex_props.begin(), vertex_props.end(), + std::size_t num_z = std::count_if(vertex_props.begin(), vertex_props.end(), std::bind2nd(property, "z")); if (num_z != 1) return false; - for (std::vector >::iterator it = + for (std::vector >::iterator it = vertex_props.begin(); it != vertex_props.end(); ++it) { if (it->first == "diffuse_red") it->first = "red"; @@ -826,11 +826,11 @@ bool MeshInput::LoadPLY (std::istream &inp) } // check if valid colors are set - std::size_t num_r = std::count_if(vertex_props.begin(), vertex_props.end(), + std::size_t num_r = std::count_if(vertex_props.begin(), vertex_props.end(), std::bind2nd(property, "red")); - std::size_t num_g = std::count_if(vertex_props.begin(), vertex_props.end(), + std::size_t num_g = std::count_if(vertex_props.begin(), vertex_props.end(), std::bind2nd(property, "green")); - std::size_t num_b = std::count_if(vertex_props.begin(), vertex_props.end(), + std::size_t num_b = std::count_if(vertex_props.begin(), vertex_props.end(), std::bind2nd(property, "blue")); std::size_t rgb_colors = num_r + num_g + num_b; if (rgb_colors != 0 && rgb_colors != 3) @@ -1214,7 +1214,7 @@ bool MeshInput::LoadBinarySTL (std::istream &rstrIn) return false; // get file size and calculate the number of facets - std::streamoff ulSize = 0; + std::streamoff ulSize = 0; std::streambuf* buf = rstrIn.rdbuf(); if (buf) { std::streamoff ulCurr; @@ -1228,7 +1228,7 @@ bool MeshInput::LoadBinarySTL (std::istream &rstrIn) // compare the calculated with the read value if (ulCt > ulFac) return false;// not a valid STL file - + MeshBuilder builder(this->_rclMesh); builder.Initialize(ulCt); @@ -1253,7 +1253,7 @@ void MeshInput::LoadXML (Base::XMLReader &reader) { MeshPointArray cPoints; MeshFacetArray cFacets; - + // reader.readElement("Mesh"); reader.readElement("Points"); @@ -1304,7 +1304,7 @@ bool MeshInput::LoadInventor (std::istream &rstrIn) boost::cmatch what; // get file size and estimate the number of lines - std::streamoff ulSize = 0; + std::streamoff ulSize = 0; std::streambuf* buf = rstrIn.rdbuf(); if (!buf) return false; @@ -1353,7 +1353,7 @@ bool MeshInput::LoadInventor (std::istream &rstrIn) clFacet.SetNormal(Base::Vector3f(fX, fY, fZ)); clFacetAry.push_back(clFacet); seq.next(true); // allow to cancel - } else + } else flag = false; } while (std::getline(rstrIn, line) && flag); } @@ -1379,7 +1379,7 @@ bool MeshInput::LoadInventor (std::istream &rstrIn) clPoint.z = (float)std::atof(what[7].first); aclPoints.push_back(clPoint); seq.next(true); // allow to cancel - } else + } else flag = false; } while (std::getline(rstrIn, line) && flag); } @@ -1661,7 +1661,7 @@ bool MeshOutput::SaveAny(const char* FileName, MeshIO::Format format) const ok = aWriter.SaveBinarySTL( str ); if (!ok) throw Base::FileException("Export of STL mesh failed",FileName); - + } else if (fileformat == MeshIO::ASTL) { MeshOutput aWriter(_rclMesh); @@ -1673,26 +1673,26 @@ bool MeshOutput::SaveAny(const char* FileName, MeshIO::Format format) const ok = aWriter.SaveAsciiSTL( str ); if (!ok) throw Base::FileException("Export of STL mesh failed",FileName); - + } else if (fileformat == MeshIO::OBJ) { // write file - if (!SaveOBJ(str)) + if (!SaveOBJ(str)) throw Base::FileException("Export of OBJ mesh failed",FileName); } else if (fileformat == MeshIO::OFF) { // write file - if (!SaveOFF(str)) + if (!SaveOFF(str)) throw Base::FileException("Export of OFF mesh failed",FileName); } else if (fileformat == MeshIO::PLY) { // write file - if (!SaveBinaryPLY(str)) + if (!SaveBinaryPLY(str)) throw Base::FileException("Export of PLY mesh failed",FileName); } else if (fileformat == MeshIO::APLY) { // write file - if (!SaveAsciiPLY(str)) + if (!SaveAsciiPLY(str)) throw Base::FileException("Export of PLY mesh failed",FileName); } else if (fileformat == MeshIO::IV) { @@ -1799,9 +1799,9 @@ bool MeshOutput::SaveAsciiSTL (std::ostream &rstrOut) const clEnd.End(); while (clIter < clEnd) { pclFacet = &(*clIter); - + // normal - rstrOut << " facet normal " << pclFacet->GetNormal().x << " " + rstrOut << " facet normal " << pclFacet->GetNormal().x << " " << pclFacet->GetNormal().y << " " << pclFacet->GetNormal().z << std::endl; rstrOut << " outer loop" << std::endl; @@ -1816,12 +1816,12 @@ bool MeshOutput::SaveAsciiSTL (std::ostream &rstrOut) const rstrOut << " endloop" << std::endl; rstrOut << " endfacet" << std::endl; - ++clIter; + ++clIter; seq.next(true);// allow to cancel } rstrOut << "endsolid Mesh" << std::endl; - + return true; } @@ -1838,7 +1838,7 @@ bool MeshOutput::SaveBinarySTL (std::ostream &rstrOut) const if (!rstrOut || rstrOut.bad() == true /*|| _rclMesh.CountFacets() == 0*/) return false; - Base::SequencerLauncher seq("saving...", _rclMesh.CountFacets() + 1); + Base::SequencerLauncher seq("saving...", _rclMesh.CountFacets() + 1); // stl_header has a length of 80 strcpy(szInfo, stl_header.c_str()); @@ -1865,7 +1865,7 @@ bool MeshOutput::SaveBinarySTL (std::ostream &rstrOut) const rstrOut.write((const char*)&(pclFacet->_aclPoints[i].z), sizeof(float)); } - // attribute + // attribute rstrOut.write((const char*)&usAtt, sizeof(usAtt)); ++clIter; @@ -1955,6 +1955,21 @@ bool MeshOutput::SaveOBJ (std::ostream &out) const } seq.next(true); // allow to cancel } + // Export normals + MeshFacetIterator clIter(_rclMesh), clEnd(_rclMesh); + const MeshGeomFacet* pclFacet; + + clIter.Begin(); + clEnd.End(); + + while (clIter < clEnd) { + pclFacet = &(*clIter); + out << "vn " << pclFacet->GetNormal().x << " " + << pclFacet->GetNormal().y << " " + << pclFacet->GetNormal().z << std::endl; + ++clIter; + seq.next(true); // allow to cancel + } if (_groups.empty()) { if (exportColorPerFace) { @@ -1967,6 +1982,7 @@ bool MeshOutput::SaveOBJ (std::ostream &out) const std::size_t index = 0; App::Color prev; + int faceIdx = 1; const std::vector& Kd = _material->diffuseColor; for (MeshFacetArray::_TConstIterator it = rFacets.begin(); it != rFacets.end(); ++it, index++) { if (index == 0 || prev != Kd[index]) { @@ -1976,25 +1992,27 @@ bool MeshOutput::SaveOBJ (std::ostream &out) const out << "usemtl material_" << (c_it - colors.begin()) << std::endl; } } - out << "f " << it->_aulPoints[0]+1 << " " - << it->_aulPoints[1]+1 << " " - << it->_aulPoints[2]+1 << std::endl; + out << "f " << it->_aulPoints[0]+1 << "//" << faceIdx << " " + << it->_aulPoints[1]+1 << "//" << faceIdx << " " + << it->_aulPoints[2]+1 << "//" << faceIdx << std::endl; seq.next(true); // allow to cancel + faceIdx++; } } else { // facet indices (no texture and normal indices) + std::size_t faceIdx = 1; for (MeshFacetArray::_TConstIterator it = rFacets.begin(); it != rFacets.end(); ++it) { - out << "f " << it->_aulPoints[0]+1 << " " - << it->_aulPoints[1]+1 << " " - << it->_aulPoints[2]+1 << std::endl; + out << "f " << it->_aulPoints[0]+1 << "//" << faceIdx << " " + << it->_aulPoints[1]+1 << "//" << faceIdx << " " + << it->_aulPoints[2]+1 << "//" << faceIdx << std::endl; seq.next(true); // allow to cancel + faceIdx++; } } } else { if (exportColorPerFace) { - // make sure to use the 'usemtl' statement as less often as possible std::vector colors = _material->diffuseColor; std::sort(colors.begin(), colors.end(), Color_Less()); @@ -2017,9 +2035,9 @@ bool MeshOutput::SaveOBJ (std::ostream &out) const } } - out << "f " << f._aulPoints[0]+1 << " " - << f._aulPoints[1]+1 << " " - << f._aulPoints[2]+1 << std::endl; + out << "f " << f._aulPoints[0]+1 << "//" << *it + 1 << " " + << f._aulPoints[1]+1 << "//" << *it + 1 << " " + << f._aulPoints[2]+1 << "//" << *it + 1 << std::endl; seq.next(true); // allow to cancel } } @@ -2029,9 +2047,9 @@ bool MeshOutput::SaveOBJ (std::ostream &out) const out << "g " << Base::Tools::escapedUnicodeFromUtf8(gt->name.c_str()) << std::endl; for (std::vector::const_iterator it = gt->indices.begin(); it != gt->indices.end(); ++it) { const MeshFacet& f = rFacets[*it]; - out << "f " << f._aulPoints[0]+1 << " " - << f._aulPoints[1]+1 << " " - << f._aulPoints[2]+1 << std::endl; + out << "f " << f._aulPoints[0]+1 << "//" << *it + 1 << " " + << f._aulPoints[1]+1 << "//" << *it + 1 << " " + << f._aulPoints[2]+1 << "//" << *it + 1 << std::endl; seq.next(true); // allow to cancel } } @@ -2149,7 +2167,7 @@ bool MeshOutput::SaveOFF (std::ostream &out) const // facet indices (no texture and normal indices) for (MeshFacetArray::_TConstIterator it = rFacets.begin(); it != rFacets.end(); ++it) { - out << "3 " << it->_aulPoints[0] + out << "3 " << it->_aulPoints[0] << " " << it->_aulPoints[1] << " " << it->_aulPoints[2] << std::endl; seq.next(true); // allow to cancel @@ -2369,12 +2387,12 @@ void MeshOutput::SaveXML (Base::Writer &writer) const writer.Stream() << writer.ind() << "_aulPoints[0] << "\" " << "p1=\"" << it->_aulPoints[1] << "\" " - << "p2=\"" << it->_aulPoints[2] << "\" " + << "p2=\"" << it->_aulPoints[2] << "\" " << "n0=\"" << it->_aulNeighbours[0] << "\" " << "n1=\"" << it->_aulNeighbours[1] << "\" " << "n2=\"" << it->_aulNeighbours[2] << "\"/>" << std::endl; - } + } writer.decInd(); writer.Stream() << writer.ind() << "" << std::endl; @@ -2624,7 +2642,7 @@ bool MeshOutput::SaveVRML (std::ostream &rstrOut) const Base::BoundBox3f clBB = _rclMesh.GetBoundBox(); - Base::SequencerLauncher seq("Saving VRML file...", + Base::SequencerLauncher seq("Saving VRML file...", _rclMesh.CountPoints() + _rclMesh.CountFacets()); rstrOut << "#VRML V2.0 utf8\n";