void cloth::bilateral(phys::system& system) { using namespace math; core::each( boost::edges(mesh), [&](const mesh_type::edge_descriptor& e) { natural i = boost::source(e, mesh); natural j = boost::target(e, mesh); auto info = mesh[e]; const vec3 diff = dofs[i].g() - dofs[j].g(); if( diff.norm() < 1e-5 ) core::log("ALARRRM"); const vec3 n = diff.normalized(); auto& J = system.constraint.bilateral.matrix; real norm = 2 * std::sqrt( 2 * diff.squaredNorm() ); real scale = 1/norm; J(info.key, &dofs[i]) = scale * 2 * diff.transpose(); // n.transpose(); J(info.key, &dofs[j]) = -2 * scale * diff.transpose(); // - n.transpose(); auto& b = system.constraint.bilateral.values; b(info.key).setZero(); auto& c = system.constraint.bilateral.corrections; c(info.key).setConstant( scale * (info.rest * info.rest - diff.squaredNorm()) ); }); }
/** * @brief rodrigue_matrix Calculate Rotational matrix by rotational axis and angle * @param n: rotational axis * @param c: cos value of rotational angle * @return */ mat3 rodrigue_matrix(const vec3& n, float c) { mat3 rom = mat3::Identity(); mat3 N; N << 0.00f, +n(2), -n(1), -n(2), 0.00f, +n(0), +n(1), -n(0), 0.00f; rom *= c; rom += (1.0f - c) * n * n.transpose(); rom += sqrt(1.0f - c * c) * N; return rom; }
mat33 getMatrix(vec3 vec, double alpha) { mat33 res; mat33 I; for(int i=0;i<3;++i){ for(int j=0;j<3;++j){ I(i,j)=(i==j)?1.0:.0; } } vec.normalize(); mat33 E=crossProductMat(vec); //print(E); //print(I); //std::cout<<vec.transpose()<<"\n"; res=cos(alpha)*I+(1-cos(alpha))*vec*vec.transpose()-sin(alpha)*E; return res; }
void graph::reset(math::natural n) { width = n; height = n; obj.resize( width * height); constraint.mesh = mesh_type( width * height ); auto pos = [&](natural i) -> vec3& { return obj[i].conf; }; auto vel = [&](natural i) -> vec3& { return obj[i].velocity; }; auto edge = [&](real rest) -> edge_type { edge_type res; res.rest = rest; res.constraint = new phys::constraint::bilateral(1); return res; }; // place vertices for(natural i = 0 ; i < n * n; ++i ) { const natural x = i / width; const natural y = i % width; pos(i) = (sceneRadius()/2) * vec3(y, 0, x) / width; vel(i).setZero(); } // create edges for(natural i = 0 ; i < n * n; ++i ) { const natural x = i / width; const natural y = i % width; bool ok_height = (x < height - 1); bool ok_width = (y < width - 1); if( ok_height ) { real rest = (pos(i) - pos(i + width)).norm(); boost::add_edge(i, i + width, edge(rest), constraint.mesh); } if( ok_width ) { real rest = (pos(i) - pos(i + 1)).norm(); boost::add_edge(i, i + 1, edge(rest), constraint.mesh); } if( ok_height && ok_width ) { // real rest = (pos(i) - pos(i + width + 1)).norm(); // boost::add_edge(i, i + width + 1, edge(rest), constraint.mesh); // rest = (pos(i + 1) - pos(i + width)).norm(); // boost::add_edge(i + 1, i + width, edge(rest), constraint.mesh); } } frame[0]->transform( SE3::translation( pos(0) ) ); frame[1]->transform( SE3::translation( pos(width - 1) ) ); system.clear(); // masses core::each( obj, [&](const obj_type& o) { system.mass[ &o ].setIdentity(3, 3); system.resp[ &o ].setIdentity(3, 3); }); constraint.lambda.clear(); constraint.update.clear(); // setup constraints core::each( boost::edges(constraint.mesh), [&](const mesh_type::edge_descriptor& e) { auto c = constraint.mesh[e].constraint; natural i = boost::source(e, constraint.mesh); natural j = boost::target(e, constraint.mesh); const real rest = constraint.mesh[e].rest; constraint.update[c] = [&,i,j,c,e,rest] { const vec3 diff = obj[i].conf - obj[j].conf; const vec3 n = diff.normalized(); auto& row = system.constraint.bilateral.matrix[ c ]; row[ &obj[i] ] = n.transpose(); row[ &obj[j] ] = -n.transpose(); const real gamma = 1; system.constraint.bilateral.values[ c ] = vec1::Zero(); system.constraint.bilateral.corrections[ c ] = gamma * vec1::Constant( (rest - diff.norm()) ); if( solver ) { constraint.mesh[e].acyclic = solver->acyclic().id.constraint.find(c) != solver->acyclic().id.constraint.end(); } }; }); constraint.fixed[ frame[0] ].dof = 0; constraint.fixed[ frame[1] ].dof = width - 1; core::each(constraint.fixed, [&](gui::frame* f, const constraint_type::attach& a) { // constraint.update[a.key] = [&,a,f]{ // const vec3 diff = f->transform().translation() - obj[a.dof].conf; // // TODO only once // system.constraint.bilateral.matrix[a.key][&obj[a.dof].dof] = mat33::Identity(); // system.constraint.bilateral.values[a.key] = vec3::Zero(); // system.constraint.bilateral.corrections[a.key] = diff; // }; }); core::each(constraint.update, [&](phys::constraint::bilateral::key, const core::callback& u) { u(); }); // setup solver solver.reset( new solver_type(system) ); // display mesh display.mesh.clear(); for(natural i = 0 ; i < n * n; ++i ) { const natural x = i / width; const natural y = i % width; bool ok_height = (x < height - 1); bool ok_width = (y < width - 1); if( ok_height && ok_width ) { display.mesh.quads.push_back(geo::mesh::quad{i, i + 1, i + width + 1, i + width } ); } }; };