added wrapping function for libigl arap parametrization
This commit is contained in:
parent
a75dbdc05d
commit
60cc24370e
|
@ -0,0 +1,207 @@
|
|||
/****************************************************************************
|
||||
* VCGLib o o *
|
||||
* Visual and Computer Graphics Library o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2017 \/)\/ *
|
||||
* Visual Computing Lab /\/| *
|
||||
* ISTI - Italian National Research Council | *
|
||||
* \ *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
/* Optimizes given UV-mapping with
|
||||
* [ARAP parametrization]
|
||||
* (minimizes area and angle distortions).
|
||||
*
|
||||
* Needs:
|
||||
* (-) per-vertex texture coords
|
||||
* (-) per-vertex flags to fix boundaries
|
||||
* Fixed vertices are the flagged ones.
|
||||
* By default: BORDER or SELECTED verts are fixed.
|
||||
* (use fixedMask parameter to customize)
|
||||
*
|
||||
* Example of usage:
|
||||
* MyMesh m;
|
||||
* ...
|
||||
* vcg::tri::UpdateFlags<MeshType>::Clear(m);
|
||||
* vcg::tri::UpdateFlags<MyMesh>::VertexBorderFromNone(m);
|
||||
* vcg::tri::OptimizeUV_ARAP(m);
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __VCG_IGL_ARAP_PARAMETRIZATION
|
||||
#define __VCG_IGL_ARAP_PARAMETRIZATION
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <igl/arap.h>
|
||||
#include <vcg/complex/algorithms/mesh_to_matrix.h>
|
||||
#include <vcg/complex/algorithms/clean.h>
|
||||
#include <vcg/complex/algorithms/update/flag.h>
|
||||
#include <wrap/igl/lscm_parametrization.h>
|
||||
|
||||
namespace vcg {
|
||||
namespace tri {
|
||||
|
||||
template<class MeshType>
|
||||
void OptimizeUV_ARAP(
|
||||
MeshType& m,
|
||||
unsigned int iterations = 100,
|
||||
unsigned int fixedMask = MeshType::VertexType::BORDER | MeshType::VertexType::SELECTED,
|
||||
bool generateInitialGuess = true)
|
||||
{
|
||||
|
||||
// check requirements
|
||||
vcg::tri::RequirePerVertexTexCoord(m);
|
||||
vcg::tri::RequirePerVertexFlags (m);
|
||||
vcg::tri::RequireCompactness (m);
|
||||
|
||||
if (m.vert.size() <= 1 || m.face.size() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// build fixed points data
|
||||
int nFixed = 0;
|
||||
if (fixedMask != 0)
|
||||
{
|
||||
for (size_t i=0; i<m.vert.size(); i++)
|
||||
{
|
||||
if (m.vert[i].Flags() & fixedMask) nFixed++;
|
||||
}
|
||||
}
|
||||
|
||||
// all fixed, nothing to do? get out to avoid crashes
|
||||
if (nFixed == m.vert.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (generateInitialGuess)
|
||||
{
|
||||
// if not enough vertices are fixed, initialize manually fixed points
|
||||
// else initialize with the provided fixed values
|
||||
InitializeArapWithLSCM(m, (nFixed < 2) ? 0 : fixedMask);
|
||||
}
|
||||
|
||||
Eigen::MatrixXd V;
|
||||
Eigen::MatrixXi F;
|
||||
Eigen::VectorXi b;
|
||||
Eigen::MatrixXd bc;
|
||||
Eigen::MatrixXd V_uv;
|
||||
vcg::tri::MeshToMatrix<MeshType>::GetTriMeshData(m, F, V);
|
||||
vcg::tri::MeshToMatrix<MeshType>::GetUVData(m, V_uv);
|
||||
|
||||
b.resize(nFixed);
|
||||
bc.resize(nFixed,2);
|
||||
for (size_t i=0,k=0; i<(int)m.vert.size(); i++)
|
||||
{
|
||||
if (m.vert[i].Flags() & fixedMask)
|
||||
{
|
||||
b(k) = i;
|
||||
bc(k,0) = m.vert[i].T().P()[0];
|
||||
bc(k,1) = m.vert[i].T().P()[1];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add dynamic regularization to avoid to specify boundary conditions
|
||||
::igl::ARAPData arap_data;
|
||||
arap_data.with_dynamics = true;
|
||||
arap_data.max_iter = iterations;
|
||||
|
||||
// compute ARAP parametrization
|
||||
::igl::arap_precomputation(V, F, 2, b, arap_data);
|
||||
::igl::arap_solve(bc, arap_data, V_uv);
|
||||
|
||||
// copy results back to mesh
|
||||
for (size_t i=0; i<m.vert.size(); i++)
|
||||
{
|
||||
m.vert[i].T().P()[0] = V_uv(i,0);
|
||||
m.vert[i].T().P()[1] = V_uv(i,1);
|
||||
}
|
||||
}
|
||||
|
||||
template <class MeshType>
|
||||
void InitializeArapWithLSCM(MeshType & m, unsigned int fixedMask = 0)
|
||||
{
|
||||
typedef typename MeshType::ScalarType ScalarType;
|
||||
typedef typename MeshType::CoordType CoordType;
|
||||
typedef typename MeshType::VertexType::TexCoordType::PointType TexPointType;
|
||||
typedef typename TexPointType::ScalarType TexScalarType;
|
||||
|
||||
if (fixedMask == 0)
|
||||
{
|
||||
// manually select fixed vertices
|
||||
vcg::tri::UpdateFlags<MeshType>::Clear(m);
|
||||
|
||||
int fixed0, fixed1 = -1;
|
||||
ScalarType minD0 = std::numeric_limits<ScalarType>::max();
|
||||
ScalarType minD1 = std::numeric_limits<ScalarType>::max();
|
||||
for (size_t i=0; i<m.vert.size(); i++)
|
||||
{
|
||||
const ScalarType testD0 =(m.vert[i].P() - m.bbox.min).Norm();
|
||||
const ScalarType testD1 =(m.vert[i].P() - m.bbox.max).Norm();
|
||||
if (testD0 < minD0)
|
||||
{
|
||||
fixed0 = i;
|
||||
minD0 = testD0;
|
||||
}
|
||||
if (testD1 < minD1)
|
||||
{
|
||||
fixed1 = i;
|
||||
minD1 = testD1;
|
||||
}
|
||||
}
|
||||
assert(fixed0 >= 0);
|
||||
assert(fixed1 >= 0);
|
||||
assert(fixed0 != fixed1);
|
||||
|
||||
//then select them
|
||||
m.vert[fixed0].SetS();
|
||||
m.vert[fixed1].SetS();
|
||||
m.vert[fixed0].T().P() = TexPointType(0,0);
|
||||
m.vert[fixed1].T().P() = TexPointType(1,1);
|
||||
|
||||
fixedMask = MeshType::VertexType::SELECTED;
|
||||
}
|
||||
|
||||
vcg::tri::OptimizeUV_LSCM(m, fixedMask);
|
||||
|
||||
// Rescale the parametrization to match the 3D area
|
||||
ScalarType meshArea2D = 0;
|
||||
ScalarType meshArea3D = 0;
|
||||
|
||||
for (size_t i=0; i<m.face.size(); i++)
|
||||
{
|
||||
vcg::Triangle2<TexScalarType> t2(m.face[i].V(0)->T().P(),
|
||||
m.face[i].V(1)->T().P(),
|
||||
m.face[i].V(2)->T().P());
|
||||
meshArea2D += ScalarType(fabs(((t2.P(1) - t2.P(0)) ^ (t2.P(2) - t2.P(0)))/2));
|
||||
meshArea3D += vcg::DoubleArea(m.face[i])/2;
|
||||
}
|
||||
|
||||
ScalarType scaleFact = std::sqrt(meshArea3D / meshArea2D);
|
||||
|
||||
for (size_t i=0; i<m.vert.size(); i++)
|
||||
{
|
||||
TexPointType & UVCoord = m.vert[i].T().P();
|
||||
UVCoord *= scaleFact;
|
||||
}
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif // __VCG_IGL_ARAP_PARAMETRIZATION
|
Loading…
Reference in New Issue