From a2a5b774aac766a87b2abba4d1d3f27d5b5809c0 Mon Sep 17 00:00:00 2001 From: Jeremy Hu Date: Thu, 29 Nov 2018 11:55:55 +0930 Subject: [PATCH] Fix uvunwrap The As-Rigid-As-Possible method of parametrization sometimes failed, so added Least-Squares-Conformal-Maps method as a fallback option. --- thirdparty/simpleuv/simpleuv/parametrize.cpp | 100 +++++++++++++------ 1 file changed, 71 insertions(+), 29 deletions(-) diff --git a/thirdparty/simpleuv/simpleuv/parametrize.cpp b/thirdparty/simpleuv/simpleuv/parametrize.cpp index 176f780c..2e01ac26 100644 --- a/thirdparty/simpleuv/simpleuv/parametrize.cpp +++ b/thirdparty/simpleuv/simpleuv/parametrize.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -8,35 +9,9 @@ namespace simpleuv { -// Modified from the libigl example code -// https://github.com/libigl/libigl/blob/master/tutorial/503_ARAPParam/main.cpp -bool parametrize(const std::vector &verticies, - const std::vector &faces, - std::vector &vertexUvs) +void parametrizeUsingARAP(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, const Eigen::VectorXi &bnd, Eigen::MatrixXd &V_uv) { - if (verticies.empty() || faces.empty()) - return false; - - //qDebug() << "parametrize vertices:" << verticies.size() << "faces:" << faces.size(); - - Eigen::MatrixXd V(verticies.size(), 3); - Eigen::MatrixXi F(faces.size(), 3); - Eigen::MatrixXd V_uv; Eigen::MatrixXd initial_guess; - - for (decltype(verticies.size()) i = 0; i < verticies.size(); i++) { - const auto &vertex = verticies[i]; - V.row(i) << vertex.xyz[0], vertex.xyz[1], vertex.xyz[2]; - } - - for (decltype(faces.size()) i = 0; i < faces.size(); i++) { - const auto &face = faces[i]; - F.row(i) << face.indices[0], face.indices[1], face.indices[2]; - } - - // Compute the initial solution for ARAP (harmonic parametrization) - Eigen::VectorXi bnd; - igl::boundary_loop(F,bnd); Eigen::MatrixXd bnd_uv; igl::map_vertices_to_circle(V,bnd,bnd_uv); @@ -58,15 +33,82 @@ bool parametrize(const std::vector &verticies, V_uv = initial_guess; arap_solve(bc,arap_data,V_uv); +} +void parametrizeUsingLSCM(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, const Eigen::VectorXi &bnd, Eigen::MatrixXd &V_uv) +{ + Eigen::VectorXi b(2,1); + b(0) = bnd(0); + b(1) = bnd(round(bnd.size()/2)); + Eigen::MatrixXd bc(2,2); + bc<<0,0,1,0; + + // LSCM parametrization + igl::lscm(V,F,b,bc,V_uv); +} + +bool extractResult(const std::vector &verticies, const Eigen::MatrixXd &V_uv, std::vector &vertexUvs) +{ + vertexUvs.clear(); + auto isCoordValid = [=](float coord) { + if (std::isnan(coord) || std::isinf(coord)) + return false; + return true; + }; for (decltype(verticies.size()) i = 0; i < verticies.size(); i++) { TextureCoord coord; coord.uv[0] = V_uv.row(i)[0]; coord.uv[1] = V_uv.row(i)[1]; - vertexUvs.push_back(coord); + if (isCoordValid(coord.uv[0]) && isCoordValid(coord.uv[1])) { + vertexUvs.push_back(coord); + continue; + } + vertexUvs.clear(); + return false; } - return true; } +// Modified from the libigl example code +// https://github.com/libigl/libigl/blob/master/tutorial/503_ARAPParam/main.cpp +bool parametrize(const std::vector &verticies, + const std::vector &faces, + std::vector &vertexUvs) +{ + if (verticies.empty() || faces.empty()) + return false; + + Eigen::MatrixXd V(verticies.size(), 3); + Eigen::MatrixXi F(faces.size(), 3); + + for (decltype(verticies.size()) i = 0; i < verticies.size(); i++) { + const auto &vertex = verticies[i]; + V.row(i) << vertex.xyz[0], vertex.xyz[1], vertex.xyz[2]; + } + + for (decltype(faces.size()) i = 0; i < faces.size(); i++) { + const auto &face = faces[i]; + F.row(i) << face.indices[0], face.indices[1], face.indices[2]; + } + + Eigen::VectorXi bnd; + igl::boundary_loop(F,bnd); + + { + Eigen::MatrixXd V_uv; + parametrizeUsingARAP(V, F, bnd, V_uv); + if (extractResult(verticies, V_uv, vertexUvs)) + return true; + } + + { + Eigen::MatrixXd V_uv; + parametrizeUsingLSCM(V, F, bnd, V_uv); + if (extractResult(verticies, V_uv, vertexUvs)) + return true; + } + + return false; +} + }