|
@@ -33,6 +33,8 @@ int main(int argc, char * argv[])
|
|
|
using namespace Eigen;
|
|
using namespace Eigen;
|
|
|
using namespace std;
|
|
using namespace std;
|
|
|
using namespace igl;
|
|
using namespace igl;
|
|
|
|
|
+ // read the mesh, if the code is prepared outside of tutorial, the TUTORIAL_SHARED_PATH
|
|
|
|
|
+ // should be the data folder
|
|
|
if(!readMESH(TUTORIAL_SHARED_PATH "/octopus-low.mesh",low.V,low.T,low.F))
|
|
if(!readMESH(TUTORIAL_SHARED_PATH "/octopus-low.mesh",low.V,low.T,low.F))
|
|
|
{
|
|
{
|
|
|
cout<<"failed to load mesh"<<endl;
|
|
cout<<"failed to load mesh"<<endl;
|
|
@@ -46,25 +48,43 @@ int main(int argc, char * argv[])
|
|
|
{
|
|
{
|
|
|
Eigen::VectorXi b;
|
|
Eigen::VectorXi b;
|
|
|
{
|
|
{
|
|
|
|
|
+ // this will create a vector from 0 to V.rows()-1 where the gap is 1
|
|
|
Eigen::VectorXi J = Eigen::VectorXi::LinSpaced(high.V.rows(),0,high.V.rows()-1);
|
|
Eigen::VectorXi J = Eigen::VectorXi::LinSpaced(high.V.rows(),0,high.V.rows()-1);
|
|
|
Eigen::VectorXd sqrD;
|
|
Eigen::VectorXd sqrD;
|
|
|
Eigen::MatrixXd _2;
|
|
Eigen::MatrixXd _2;
|
|
|
cout<<"Finding closest points..."<<endl;
|
|
cout<<"Finding closest points..."<<endl;
|
|
|
|
|
+ // using J which is N by 1 instead of a matrix that represents faces of N by 3
|
|
|
|
|
+ // so that we will find the closest vertices istead of closest point on the face
|
|
|
|
|
+ // so far the two meshes are not seperated. So what we are really doing here
|
|
|
|
|
+ // is computing handles from low resolution and use that for the high resolution one
|
|
|
igl::point_mesh_squared_distance(low.V,high.V,J,sqrD,b,_2);
|
|
igl::point_mesh_squared_distance(low.V,high.V,J,sqrD,b,_2);
|
|
|
assert(sqrD.minCoeff() < 1e-7 && "low.V should exist in high.V");
|
|
assert(sqrD.minCoeff() < 1e-7 && "low.V should exist in high.V");
|
|
|
}
|
|
}
|
|
|
// force perfect positioning, rather have popping in low-res than high-res.
|
|
// force perfect positioning, rather have popping in low-res than high-res.
|
|
|
// The correct/elaborate thing to do is express original low.V in terms of
|
|
// The correct/elaborate thing to do is express original low.V in terms of
|
|
|
// linear interpolation (or extrapolation) via elements in (high.V,high.F)
|
|
// linear interpolation (or extrapolation) via elements in (high.V,high.F)
|
|
|
|
|
+
|
|
|
|
|
+ // this is to replace the vertices on low resolution
|
|
|
|
|
+ // with the vertices in high resolution. b is the list of vertices
|
|
|
|
|
+ // corresponding to the indices in high resolution which has closest
|
|
|
|
|
+ // distance to the points in low resolution
|
|
|
igl::slice(high.V,b,1,low.V);
|
|
igl::slice(high.V,b,1,low.V);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
// list of points --> list of singleton lists
|
|
// list of points --> list of singleton lists
|
|
|
std::vector<std::vector<int> > S;
|
|
std::vector<std::vector<int> > S;
|
|
|
|
|
+ // S will hav size of low.V.rows() and each list inside will have 1 element
|
|
|
igl::matrix_to_list(b,S);
|
|
igl::matrix_to_list(b,S);
|
|
|
cout<<"Computing weights for "<<b.size()<<
|
|
cout<<"Computing weights for "<<b.size()<<
|
|
|
" handles at "<<high.V.rows()<<" vertices..."<<endl;
|
|
" handles at "<<high.V.rows()<<" vertices..."<<endl;
|
|
|
// Technically k should equal 3 for smooth interpolation in 3d, but 2 is
|
|
// Technically k should equal 3 for smooth interpolation in 3d, but 2 is
|
|
|
// faster and looks OK
|
|
// faster and looks OK
|
|
|
const int k = 2;
|
|
const int k = 2;
|
|
|
|
|
+
|
|
|
|
|
+ // using all the points in low resolution as handles for the region
|
|
|
|
|
+ // it will be too expansive to use all the points in high reolution as handles
|
|
|
|
|
+ // but since low and high resembles the same thing, using points in low reesolution
|
|
|
|
|
+ // will give you similar performance
|
|
|
igl::biharmonic_coordinates(high.V,high.T,S,k,W);
|
|
igl::biharmonic_coordinates(high.V,high.T,S,k,W);
|
|
|
cout<<"Reindexing..."<<endl;
|
|
cout<<"Reindexing..."<<endl;
|
|
|
// Throw away interior tet-vertices, keep weights and indices of boundary
|
|
// Throw away interior tet-vertices, keep weights and indices of boundary
|
|
@@ -97,6 +117,7 @@ int main(int argc, char * argv[])
|
|
|
Eigen::SparseMatrix<double> M;
|
|
Eigen::SparseMatrix<double> M;
|
|
|
igl::massmatrix(low.V,low.T,igl::MASSMATRIX_TYPE_DEFAULT,M);
|
|
igl::massmatrix(low.V,low.T,igl::MASSMATRIX_TYPE_DEFAULT,M);
|
|
|
const size_t n = low.V.rows();
|
|
const size_t n = low.V.rows();
|
|
|
|
|
+ // f = ma
|
|
|
arap_data.f_ext = M * RowVector3d(0,-9.8,0).replicate(n,1);
|
|
arap_data.f_ext = M * RowVector3d(0,-9.8,0).replicate(n,1);
|
|
|
// Random initial velocities to wiggle things
|
|
// Random initial velocities to wiggle things
|
|
|
arap_data.vel = MatrixXd::Random(n,3);
|
|
arap_data.vel = MatrixXd::Random(n,3);
|
|
@@ -104,6 +125,7 @@ int main(int argc, char * argv[])
|
|
|
igl::opengl::glfw::Viewer viewer;
|
|
igl::opengl::glfw::Viewer viewer;
|
|
|
// Create one huge mesh containing both meshes
|
|
// Create one huge mesh containing both meshes
|
|
|
igl::cat(1,low.U,high.U,scene.U);
|
|
igl::cat(1,low.U,high.U,scene.U);
|
|
|
|
|
+ // need to remap the indices since we cat the V matrices
|
|
|
igl::cat(1,low.F,MatrixXi(high.F.array()+low.V.rows()),scene.F);
|
|
igl::cat(1,low.F,MatrixXi(high.F.array()+low.V.rows()),scene.F);
|
|
|
// Color each mesh
|
|
// Color each mesh
|
|
|
viewer.data().set_mesh(scene.U,scene.F);
|
|
viewer.data().set_mesh(scene.U,scene.F);
|