You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
215 lines
6.6 KiB
215 lines
6.6 KiB
/**************************************************************************** |
|
* 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: |
|
* MeshType m; |
|
* ... |
|
* vcg::tri::UpdateBounding<MeshType>::Box(m); |
|
* vcg::tri::UpdateFlags<MeshType>::Clear(m); |
|
* vcg::tri::UpdateFlags<MeshType>::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 |
|
size_t 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<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::VertexType::TexCoordType::PointType TexPointType; |
|
typedef typename TexPointType::ScalarType TexScalarType; |
|
|
|
if (fixedMask == 0) |
|
{ |
|
// automatically select 2 vertices to fix |
|
vcg::tri::UpdateFlags<MeshType>::Clear(m); |
|
|
|
int fixed0, fixed1 = -1; |
|
auto p = m.bbox.Center(); |
|
ScalarType maxDist = -1; |
|
for (size_t i=0; i<m.vert.size(); i++) |
|
{ |
|
// farthest point from the center |
|
const ScalarType dist =(m.vert[i].cP() - p).Norm(); |
|
if (dist > maxDist) |
|
{ |
|
fixed0 = i; |
|
maxDist = dist; |
|
} |
|
} |
|
maxDist = -1; |
|
p = m.vert[fixed0].cP(); |
|
for (size_t i=0; i<m.vert.size(); i++) |
|
{ |
|
// farthest point from the previous |
|
const ScalarType dist =(m.vert[i].cP() - p).Norm(); |
|
if (dist > maxDist) |
|
{ |
|
fixed1 = i; |
|
maxDist = dist; |
|
} |
|
} |
|
|
|
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
|
|
|