Fix uvunwrap

The As-Rigid-As-Possible method of parametrization sometimes failed, so added Least-Squares-Conformal-Maps method as a fallback option.
master
Jeremy Hu 2018-11-29 11:55:55 +09:30
parent aadee8df08
commit a2a5b774aa
1 changed files with 71 additions and 29 deletions

View File

@ -1,4 +1,5 @@
#include <igl/arap.h> #include <igl/arap.h>
#include <igl/lscm.h>
#include <igl/boundary_loop.h> #include <igl/boundary_loop.h>
#include <igl/harmonic.h> #include <igl/harmonic.h>
#include <igl/map_vertices_to_circle.h> #include <igl/map_vertices_to_circle.h>
@ -8,35 +9,9 @@
namespace simpleuv namespace simpleuv
{ {
// Modified from the libigl example code void parametrizeUsingARAP(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, const Eigen::VectorXi &bnd, Eigen::MatrixXd &V_uv)
// https://github.com/libigl/libigl/blob/master/tutorial/503_ARAPParam/main.cpp
bool parametrize(const std::vector<Vertex> &verticies,
const std::vector<Face> &faces,
std::vector<TextureCoord> &vertexUvs)
{ {
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; 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; Eigen::MatrixXd bnd_uv;
igl::map_vertices_to_circle(V,bnd,bnd_uv); igl::map_vertices_to_circle(V,bnd,bnd_uv);
@ -58,15 +33,82 @@ bool parametrize(const std::vector<Vertex> &verticies,
V_uv = initial_guess; V_uv = initial_guess;
arap_solve(bc,arap_data,V_uv); 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<Vertex> &verticies, const Eigen::MatrixXd &V_uv, std::vector<TextureCoord> &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++) { for (decltype(verticies.size()) i = 0; i < verticies.size(); i++) {
TextureCoord coord; TextureCoord coord;
coord.uv[0] = V_uv.row(i)[0]; coord.uv[0] = V_uv.row(i)[0];
coord.uv[1] = V_uv.row(i)[1]; 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; 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<Vertex> &verticies,
const std::vector<Face> &faces,
std::vector<TextureCoord> &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;
}
} }