|
@@ -8,6 +8,7 @@
|
|
|
#include <igl/comiso/frame_field.h>
|
|
|
#include <igl/frame_field_deformer.h>
|
|
|
#include <igl/jet.h>
|
|
|
+#include <igl/frame_to_cross_field.h>
|
|
|
|
|
|
// Input mesh
|
|
|
Eigen::MatrixXd V;
|
|
@@ -39,13 +40,29 @@ Eigen::MatrixXd FF2_deformed;
|
|
|
Eigen::MatrixXd X1_deformed;
|
|
|
Eigen::MatrixXd X2_deformed;
|
|
|
|
|
|
-// Quad mesh on deformed
|
|
|
-Eigen::MatrixXd V_quad_deformed;
|
|
|
-Eigen::MatrixXi F_quad_deformed;
|
|
|
+// Global parametrization
|
|
|
+Eigen::MatrixXd V_uv;
|
|
|
+Eigen::MatrixXi F_uv;
|
|
|
|
|
|
-// Quad mesh
|
|
|
-Eigen::MatrixXd V_quad;
|
|
|
-Eigen::MatrixXi F_quad;
|
|
|
+// Create a texture that hides the integer translation in the parametrization
|
|
|
+void line_texture(Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic> &texture_R,
|
|
|
+ Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic> &texture_G,
|
|
|
+ Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic> &texture_B)
|
|
|
+{
|
|
|
+ unsigned size = 128;
|
|
|
+ unsigned size2 = size/2;
|
|
|
+ unsigned lineWidth = 3;
|
|
|
+ texture_R.setConstant(size, size, 255);
|
|
|
+ for (unsigned i=0; i<size; ++i)
|
|
|
+ for (unsigned j=size2-lineWidth; j<=size2+lineWidth; ++j)
|
|
|
+ texture_R(i,j) = 0;
|
|
|
+ for (unsigned i=size2-lineWidth; i<=size2+lineWidth; ++i)
|
|
|
+ for (unsigned j=0; j<size; ++j)
|
|
|
+ texture_R(i,j) = 0;
|
|
|
+
|
|
|
+ texture_G = texture_R;
|
|
|
+ texture_B = texture_R;
|
|
|
+}
|
|
|
|
|
|
bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
|
|
|
{
|
|
@@ -112,8 +129,8 @@ bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
|
|
|
{
|
|
|
// Deformed with frame field
|
|
|
viewer.set_mesh(V_deformed, F);
|
|
|
- viewer.add_edges (B_deformed, B_deformed + global_scale*FF1_deformed ,Eigen::RowVector3d(1,0,0));
|
|
|
- viewer.add_edges (B_deformed, B_deformed + global_scale*FF2_deformed ,Eigen::RowVector3d(0,0,1));
|
|
|
+ viewer.add_edges (B_deformed - global_scale*FF1_deformed, B_deformed + global_scale*FF1_deformed ,Eigen::RowVector3d(1,0,0));
|
|
|
+ viewer.add_edges (B_deformed - global_scale*FF2_deformed, B_deformed + global_scale*FF2_deformed ,Eigen::RowVector3d(0,0,1));
|
|
|
viewer.set_colors(RowVector3d(1,1,1));
|
|
|
}
|
|
|
|
|
@@ -121,22 +138,34 @@ bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
|
|
|
{
|
|
|
// Deformed with cross field
|
|
|
viewer.set_mesh(V_deformed, F);
|
|
|
- viewer.add_edges (B, B + global_scale*X1_deformed ,Eigen::RowVector3d(1,0,0));
|
|
|
- viewer.add_edges (B, B + global_scale*X2_deformed ,Eigen::RowVector3d(0,0,1));
|
|
|
+ viewer.add_edges (B_deformed - global_scale*X1_deformed, B_deformed + global_scale*X1_deformed ,Eigen::RowVector3d(0,0,1));
|
|
|
+ viewer.add_edges (B_deformed - global_scale*X2_deformed, B_deformed + global_scale*X2_deformed ,Eigen::RowVector3d(0,0,1));
|
|
|
+ viewer.set_colors(RowVector3d(1,1,1));
|
|
|
}
|
|
|
|
|
|
if (key == '5')
|
|
|
{
|
|
|
- // Deformed with quad mesh
|
|
|
- viewer.set_mesh(V_quad_deformed, F_quad_deformed);
|
|
|
+ // Deformed with quad texture
|
|
|
+ viewer.set_mesh(V_deformed, F);
|
|
|
+ viewer.set_uv(V_uv,F_uv);
|
|
|
+ viewer.set_colors(RowVector3d(1,1,1));
|
|
|
+ viewer.options.show_texture = true;
|
|
|
}
|
|
|
|
|
|
if (key == '6')
|
|
|
{
|
|
|
- // Deformed with quad mesh
|
|
|
- viewer.set_mesh(V_quad, F_quad);
|
|
|
+ // Deformed with quad texture
|
|
|
+ viewer.set_mesh(V, F);
|
|
|
+ viewer.set_uv(V_uv,F_uv);
|
|
|
+ viewer.set_colors(RowVector3d(1,1,1));
|
|
|
+ viewer.options.show_texture = true;
|
|
|
}
|
|
|
|
|
|
+ // Replace the standard texture with an integer shift invariant texture
|
|
|
+ Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic> texture_R, texture_G, texture_B;
|
|
|
+ line_texture(texture_R, texture_G, texture_B);
|
|
|
+ viewer.set_texture(texture_R, texture_B, texture_G);
|
|
|
+
|
|
|
return false;
|
|
|
}
|
|
|
|
|
@@ -160,23 +189,6 @@ int main(int argc, char *argv[])
|
|
|
b = temp.block(0,0,temp.rows(),1).cast<int>();
|
|
|
bc1 = temp.block(0,1,temp.rows(),3);
|
|
|
bc2 = temp.block(0,4,temp.rows(),3);
|
|
|
-
|
|
|
-// // Load a mesh in OBJ format
|
|
|
-// igl::readOFF("../shared/planexy.off", V, F);
|
|
|
-//
|
|
|
-// // Compute face barycenters
|
|
|
-// igl::barycenter(V, F, B);
|
|
|
-//
|
|
|
-// // Compute scale for visualizing fields
|
|
|
-// global_scale = .2*igl::avg_edge_length(V, F);
|
|
|
-//
|
|
|
-// b.resize(1);
|
|
|
-// b << 0;
|
|
|
-// bc1.resize(1,3);
|
|
|
-// bc1 << (V.row(F(0,0)) - V.row(F(0,1))).normalized();
|
|
|
-// MatrixXd B1,B2,B3;
|
|
|
-// igl::local_basis(V,F,B1,B2,B3);
|
|
|
-// bc2 = igl::rotate_vectors(bc1, VectorXd::Constant(1,M_PI/2), B1, B2);
|
|
|
|
|
|
// Interpolate the frame field
|
|
|
igl::frame_field(V, F, b, bc1, bc2, FF1, FF2);
|
|
@@ -187,9 +199,48 @@ int main(int argc, char *argv[])
|
|
|
// Compute face barycenters deformed mesh
|
|
|
igl::barycenter(V_deformed, F, B_deformed);
|
|
|
|
|
|
+ // Find the closest crossfield to the deformed frame field
|
|
|
+ igl::frame_to_cross_field(V,F,FF1_deformed,FF2_deformed,X1_deformed);
|
|
|
+
|
|
|
+ // Find a smooth crossfield that interpolates the deformed constraints
|
|
|
+ MatrixXd bc_x(b.size(),3);
|
|
|
+ for (unsigned i=0; i<b.size();++i)
|
|
|
+ bc_x.row(i) = X1_deformed.row(b(i));
|
|
|
+
|
|
|
+ VectorXd S;
|
|
|
+ igl::nrosy(
|
|
|
+ V,
|
|
|
+ F,
|
|
|
+ b,
|
|
|
+ bc_x,
|
|
|
+ VectorXi(),
|
|
|
+ VectorXd(),
|
|
|
+ MatrixXd(),
|
|
|
+ 4,
|
|
|
+ 0.5,
|
|
|
+ X1_deformed,
|
|
|
+ S);
|
|
|
+
|
|
|
+ // The other representative of the cross field is simply rotated by 90 degrees
|
|
|
+ MatrixXd B1,B2,B3;
|
|
|
+ igl::local_basis(V_deformed,F,B1,B2,B3);
|
|
|
+ X2_deformed = igl::rotate_vectors(X1_deformed, VectorXd::Constant(1,M_PI/2), B1, B2);
|
|
|
+
|
|
|
+ // Global seamless parametrization
|
|
|
+ igl::miq(V_deformed,
|
|
|
+ F,
|
|
|
+ X1_deformed,
|
|
|
+ X2_deformed,
|
|
|
+ V_uv,
|
|
|
+ F_uv,
|
|
|
+ 60.0,
|
|
|
+ 5.0,
|
|
|
+ false,
|
|
|
+ 0);
|
|
|
+
|
|
|
igl::Viewer viewer;
|
|
|
// Plot the original mesh with a texture parametrization
|
|
|
- key_down(viewer,'1',0);
|
|
|
+ key_down(viewer,'6',0);
|
|
|
|
|
|
// Launch the viewer
|
|
|
viewer.callback_key_down = &key_down;
|