123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- #include <igl/avg_edge_length.h>
- #include <igl/barycenter.h>
- #include <igl/frame_field_deformer.h>
- #include <igl/frame_to_cross_field.h>
- #include <igl/jet.h>
- #include <igl/local_basis.h>
- #include <igl/readDMAT.h>
- #include <igl/readOBJ.h>
- #include <igl/rotate_vectors.h>
- #include <igl/comiso/nrosy.h>
- #include <igl/comiso/miq.h>
- #include <igl/comiso/frame_field.h>
- #include <igl/viewer/Viewer.h>
- #include "tutorial_shared_path.h"
- // Input mesh
- Eigen::MatrixXd V;
- Eigen::MatrixXi F;
- // Face barycenters
- Eigen::MatrixXd B;
- // Scale for visualizing the fields
- double global_scale;
- // Input frame field constraints
- Eigen::VectorXi b;
- Eigen::MatrixXd bc1;
- Eigen::MatrixXd bc2;
- // Interpolated frame field
- Eigen::MatrixXd FF1, FF2;
- // Deformed mesh
- Eigen::MatrixXd V_deformed;
- Eigen::MatrixXd B_deformed;
- // Frame field on deformed
- Eigen::MatrixXd FF1_deformed;
- Eigen::MatrixXd FF2_deformed;
- // Cross field on deformed
- Eigen::MatrixXd X1_deformed;
- Eigen::MatrixXd X2_deformed;
- // Global parametrization
- Eigen::MatrixXd V_uv;
- Eigen::MatrixXi F_uv;
- // Create a texture that hides the integer translation in the parametrization
- void line_texture(Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> &texture_R,
- Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> &texture_G,
- Eigen::Matrix<unsigned 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& viewer, unsigned char key, int modifier)
- {
- using namespace std;
- using namespace Eigen;
- if (key <'1' || key >'6')
- return false;
- viewer.data.clear();
- viewer.core.show_lines = false;
- viewer.core.show_texture = false;
- if (key == '1')
- {
- // Frame field constraints
- viewer.data.set_mesh(V, F);
- MatrixXd F1_t = MatrixXd::Zero(FF1.rows(),FF1.cols());
- MatrixXd F2_t = MatrixXd::Zero(FF2.rows(),FF2.cols());
- // Highlight in red the constrained faces
- MatrixXd C = MatrixXd::Constant(F.rows(),3,1);
- for (unsigned i=0; i<b.size();++i)
- {
- C.row(b(i)) << 1, 0, 0;
- F1_t.row(b(i)) = bc1.row(i);
- F2_t.row(b(i)) = bc2.row(i);
- }
- viewer.data.set_colors(C);
- MatrixXd C1,C2;
- VectorXd K1 = F1_t.rowwise().norm();
- VectorXd K2 = F2_t.rowwise().norm();
- igl::jet(K1,true,C1);
- igl::jet(K2,true,C2);
- viewer.data.add_edges(B - global_scale*F1_t, B + global_scale*F1_t ,C1);
- viewer.data.add_edges(B - global_scale*F2_t, B + global_scale*F2_t ,C2);
- }
- if (key == '2')
- {
- // Frame field
- viewer.data.set_mesh(V, F);
- MatrixXd C1,C2;
- VectorXd K1 = FF1.rowwise().norm();
- VectorXd K2 = FF2.rowwise().norm();
- igl::jet(K1,true,C1);
- igl::jet(K2,true,C2);
- viewer.data.add_edges(B - global_scale*FF1, B + global_scale*FF1 ,C1);
- viewer.data.add_edges(B - global_scale*FF2, B + global_scale*FF2 ,C2);
- // Highlight in red the constrained faces
- MatrixXd C = MatrixXd::Constant(F.rows(),3,1);
- for (unsigned i=0; i<b.size();++i)
- C.row(b(i)) << 1, 0, 0;
- viewer.data.set_colors(C);
- }
- if (key == '3')
- {
- // Deformed with frame field
- viewer.data.set_mesh(V_deformed, F);
- viewer.data.add_edges(B_deformed - global_scale*FF1_deformed, B_deformed + global_scale*FF1_deformed ,Eigen::RowVector3d(1,0,0));
- viewer.data.add_edges(B_deformed - global_scale*FF2_deformed, B_deformed + global_scale*FF2_deformed ,Eigen::RowVector3d(0,0,1));
- viewer.data.set_colors(RowVector3d(1,1,1));
- }
- if (key == '4')
- {
- // Deformed with cross field
- viewer.data.set_mesh(V_deformed, F);
- viewer.data.add_edges(B_deformed - global_scale*X1_deformed, B_deformed + global_scale*X1_deformed ,Eigen::RowVector3d(0,0,1));
- viewer.data.add_edges(B_deformed - global_scale*X2_deformed, B_deformed + global_scale*X2_deformed ,Eigen::RowVector3d(0,0,1));
- viewer.data.set_colors(RowVector3d(1,1,1));
- }
- if (key == '5')
- {
- // Deformed with quad texture
- viewer.data.set_mesh(V_deformed, F);
- viewer.data.set_uv(V_uv,F_uv);
- viewer.data.set_colors(RowVector3d(1,1,1));
- viewer.core.show_texture = true;
- }
- if (key == '6')
- {
- // Deformed with quad texture
- viewer.data.set_mesh(V, F);
- viewer.data.set_uv(V_uv,F_uv);
- viewer.data.set_colors(RowVector3d(1,1,1));
- viewer.core.show_texture = true;
- }
- // Replace the standard texture with an integer shift invariant texture
- Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> texture_R, texture_G, texture_B;
- line_texture(texture_R, texture_G, texture_B);
- viewer.data.set_texture(texture_R, texture_B, texture_G);
- viewer.core.align_camera_center(viewer.data.V,viewer.data.F);
- return false;
- }
- int main(int argc, char *argv[])
- {
- using namespace Eigen;
- // Load a mesh in OBJ format
- igl::readOBJ(TUTORIAL_SHARED_PATH "/bumpy-cube.obj", V, F);
- // Compute face barycenters
- igl::barycenter(V, F, B);
- // Compute scale for visualizing fields
- global_scale = .2*igl::avg_edge_length(V, F);
- // Load constraints
- MatrixXd temp;
- igl::readDMAT(TUTORIAL_SHARED_PATH "/bumpy-cube.dmat",temp);
- 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);
- // Interpolate the frame field
- igl::comiso::frame_field(V, F, b, bc1, bc2, FF1, FF2);
- // Deform the mesh to transform the frame field in a cross field
- igl::frame_field_deformer(
- V,F,FF1,FF2,V_deformed,FF1_deformed,FF2_deformed);
- // 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_deformed,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::comiso::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::comiso::miq(V_deformed,
- F,
- X1_deformed,
- X2_deformed,
- V_uv,
- F_uv,
- 60.0,
- 5.0,
- false,
- 2);
- igl::viewer::Viewer viewer;
- // Plot the original mesh with a texture parametrization
- key_down(viewer,'6',0);
- // Launch the viewer
- viewer.callback_key_down = &key_down;
- viewer.launch();
- }
|