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()) ); }); }
Quaternion::Quaternion(vec3 Axis,float Angle) { float Temp1,Temp2; Temp1 = Axis.norm(); Q_ASSERT(Temp1 != 0 && "Quaternion Axis is zero!"); Temp2 = sinf(Angle * 0.5F) / Temp1; SetValues(Axis.x * Temp2,Axis.y * Temp2,Axis.z * Temp2,cosf(Angle * 0.5F)); }
quat::quat(const vec3& axis, nv_scalar angle) { nv_scalar len = axis.norm(); if (len) { nv_scalar invLen = 1 / len; nv_scalar angle2 = angle / 2; nv_scalar scale = _sin(angle2) * invLen; x = scale * axis[0]; y = scale * axis[1]; z = scale * axis[2]; w = _cos(angle2); } }
/// Returns the normalized vector of a vector. inline vec3 normalize(const vec3& v) { return (1 / v.norm()) * v; }
inline T cos(const vec3& other) { return *this * other / norm() / other.norm(); }
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 } ); } }; };