-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathmain.cpp
168 lines (143 loc) · 5.89 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include "polyscope/curve_network.h"
#include "polyscope/point_cloud.h"
#include "polyscope/polyscope.h"
#include "polyscope/surface_mesh.h"
#include "args/args.hxx"
#include <igl/read_triangle_mesh.h>
#include <igl/cotmatrix_intrinsic.h>
#include <igl/massmatrix_intrinsic.h>
#include <Eigen/Core>
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <build_intrinsic_info.h>
#include <chrono>
#include <coarsen_mesh.h>
#include <remove_unreferenced_intrinsic.h>
#include <query_texture_barycentric.h>
#include <bake_texture.h>
#include <connected_components.h>
int main(int argc, char* argv[]) {
using namespace Eigen;
using namespace std;
using namespace global_variables;
using namespace std::chrono;
// Configure the argument parser
args::ArgumentParser parser("Intrinsic Prolongation");
args::Positional<std::string> filename_arg(parser, "mesh",
"Mesh to be coarsened. (default='../../meshes/spot.obj'). Must have UV coordinates");
args::Positional<int> n_coarse_vertices_arg(parser, "n_coarse_vertices",
"Number of coarse vertices to leave. (default='500')");
args::ValueFlag<double> weight_arg(parser, "area_weight",
"Influence of vertex area on coarsening. 0: none, 1: pure area weighting. (default='0')", {'w',"area_weight"});
args::ValueFlag<int> texture_width_arg(parser, "texture_width",
"texture width. (default='2048')", {'u',"texture_width"});
args::ValueFlag<std::string> texture_path_arg(parser, "texture_path",
"File to save texture to. Texture will be saved as a png. If not set, the texture is not saved", {'t',"texture_path"});
args::HelpFlag help(parser, "help", "Display this help menu", {'h', "help"});
// Parse args
try {
parser.ParseCLI(argc, argv);
} catch (args::Help) {
std::cout << parser;
return 0;
} catch (const args::ParseError& e) {
std::cerr << e.what() << std::endl;
std::cerr << parser;
return 1;
}
std::string filename = filename_arg ? args::get(filename_arg) : "../../meshes/spot.obj";
int n_coarse_vertices = n_coarse_vertices_arg ? args::get(n_coarse_vertices_arg) : 500;
double weight = weight_arg ? args::get(weight_arg) : 0;
int tex_width = texture_width_arg ? args::get(texture_width_arg) : 2048;
bool using_texture = tex_width > 0;
// load mesh
MatrixXd VO, UV, NV;
MatrixXi F, FO, UF, NF;
{
igl::readOBJ(filename, VO, UV, NV, FO, UF, NF);
}
if (UV.rows() == 0) {
std::cout << "Error: input mesh has no UV coordinates" << std::endl;
exit(1);
}
if (n_coarse_vertices < 0 ) {
std::cout << "Error: target number of vertices is negative: " << n_coarse_vertices << std::endl;
exit(1);
} else if (n_coarse_vertices >= VO.rows()) {
std::cout << "Warning: target number of vertices is greater than input mesh size." << std::endl;
std::cout <<"\t target number of vertices: " << n_coarse_vertices << std::endl;
std::cout <<"\t input mesh size: " << VO.rows() << std::endl;
n_coarse_vertices = VO.rows();
}
int tex_size = (using_texture) ? tex_width * tex_width : 0;
MatrixXd bary_coords;
VectorXi bary_faces;
Matrix<bool, Dynamic, 1> hit_mask;
if (using_texture)
query_texture_barycentric(UV, UF, tex_width, bary_faces, bary_coords, hit_mask);
MatrixXi G; // glue map
MatrixXd l; // edge lengths
MatrixXd A; // angular coordinates
MatrixXi v2fs; // vertex to faceside map
build_intrinsic_info(VO, FO, G, l, A, v2fs);
F = FO;
// Check if mesh is connected
VectorXi v_ids, f_ids;
int n_components;
connected_components(FO, G, n_components, v_ids, f_ids);
if (n_components != 1) {
std::cout << "WARNING: input mesh has " << n_components << " connected components. Simplification may behave unexpectedly when the input mesh is not connected." << std::endl;
}
int total_removal = VO.rows() - n_coarse_vertices;
MatrixXd BC;
vector<vector<int>> F2V;
int nV = v2fs.rows();
int nF = F.rows();
BC.resize(nV + tex_size, 3);
BC.setConstant(0.0);
F2V.resize(nF);
size_t iP = 0;
for (int i = 0; i < tex_size; i++) {
if (hit_mask(i)) {
BC.row(nV + iP) = bary_coords.row(i);
F2V[bary_faces(i)].push_back(nV + iP);
iP++;
}
}
BC.conservativeResize(nV + iP, 3); // only keep active pixels
coarsen_mesh(total_removal, weight, F, G, l, A, v2fs, BC, F2V);
cout << "removed " << total_removal << " vertices" << endl;
std::vector<unsigned char> texture;
bake_texture(texture, F, F2V, hit_mask, nV);
if (texture_path_arg) {
std::string texture_path = args::get(texture_path_arg);
bake_texture(texture_path, texture);
}
// removed unreferenced vertices
map<int, int> IMV, IMF;
VectorXi vIdx, fIdx;
remove_unreferenced_intrinsic(F, G, l, A, v2fs, F2V, IMV, IMF, vIdx, fIdx);
MatrixXd V;
igl::slice(VO,vIdx,1,V);
// set up scene in polyscope
polyscope::init();
auto psMesh = polyscope::registerSurfaceMesh("input mesh", VO, FO);
polyscope::registerSurfaceMesh("coarsened mesh (with wrong edge length)", V, F);
if (using_texture) {
// convert parameterization to polyscope's desired input format
Eigen::Matrix<glm::vec2, Dynamic, 1> parameterization(3 * UF.rows());
for (int iF = 0; iF < UF.rows(); iF++) {
for (int iC = 0; iC < 3; iC++) {
parameterization(3 * iF + iC) = glm::vec2{UV(UF(iF, iC), 0), UV(UF(iF, iC), 1)};
}
}
auto q = psMesh->addParameterizationQuantity("intrinsic triangulation", parameterization)
->setTexture(tex_width, tex_width, texture,
polyscope::TextureFormat::RGBA8);
q->setEnabled(true);
q->setStyle(polyscope::ParamVizStyle::TEXTURE);
q->setCheckerSize(1);
}
polyscope::view::lookAt(glm::vec3{1.5, 1.5, 3}, glm::vec3{0., 0., 0.});
polyscope::show();
}