Ai
1 Star 0 Fork 2

FantasyVR/position-based-dynamic-GPU

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
PositionBasedElasticRods.cpp 43.64 KB
一键复制 编辑 原始数据 按行查看 历史
李开诚 提交于 2020-06-04 13:39 +08:00 . first commit
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363
#include "PositionBasedElasticRods.h"
#include "PositionBasedDynamics/MathFunctions.h"
#include "Utils/Logger.h"
#define _USE_MATH_DEFINES
#include "math.h"
using namespace PBD;
const Real eps = static_cast<Real>(1e-6);
const int permutation[3][3] = {
0, 2, 1,
1, 0, 2,
2, 1, 0
};
// ----------------------------------------------------------------------------------------------
bool PositionBasedCosseratRods::solve_StretchShearConstraint(
const Vector3r& p0, Real invMass0,
const Vector3r& p1, Real invMass1,
const Quaternionr& q0, Real invMassq0,
const Vector3r& stretchingAndShearingKs,
const Real restLength,
Vector3r& corr0, Vector3r& corr1, Quaternionr& corrq0)
{
Vector3r d3; //third director d3 = q0 * e_3 * q0_conjugate
d3[0] = static_cast<Real>(2.0) * (q0.x() * q0.z() + q0.w() * q0.y());
d3[1] = static_cast<Real>(2.0) * (q0.y() * q0.z() - q0.w() * q0.x());
d3[2] = q0.w() * q0.w() - q0.x() * q0.x() - q0.y() * q0.y() + q0.z() * q0.z();
Vector3r gamma = (p1 - p0) / restLength - d3;
gamma /= (invMass1 + invMass0) / restLength + invMassq0 * static_cast<Real>(4.0)*restLength + eps;
if (std::abs(stretchingAndShearingKs[0] - stretchingAndShearingKs[1]) < eps && std::abs(stretchingAndShearingKs[0] - stretchingAndShearingKs[2]) < eps) //all Ks are approx. equal
for (int i = 0; i<3; i++) gamma[i] *= stretchingAndShearingKs[i];
else //diffenent stretching and shearing Ks. Transform diag(Ks[0], Ks[1], Ks[2]) into world space using Ks_w = R(q0) * diag(Ks[0], Ks[1], Ks[2]) * R^T(q0) and multiply it with gamma
{
Matrix3r R = q0.toRotationMatrix();
gamma = (R.transpose() * gamma).eval();
for (int i = 0; i<3; i++) gamma[i] *= stretchingAndShearingKs[i];
gamma = (R * gamma).eval();
}
corr0 = invMass0 * gamma;
corr1 = -invMass1 * gamma;
Quaternionr q_e_3_bar(q0.z(), -q0.y(), q0.x(), -q0.w()); //compute q*e_3.conjugate (cheaper than quaternion product)
corrq0 = Quaternionr(0.0, gamma.x(), gamma.y(), gamma.z()) * q_e_3_bar;
corrq0.coeffs() *= static_cast<Real>(2.0) * invMassq0 * restLength;
return true;
}
// ----------------------------------------------------------------------------------------------
bool PositionBasedCosseratRods::solve_BendTwistConstraint(
const Quaternionr& q0, Real invMassq0,
const Quaternionr& q1, Real invMassq1,
const Vector3r& bendingAndTwistingKs,
const Quaternionr& restDarbouxVector,
Quaternionr& corrq0, Quaternionr& corrq1)
{
Quaternionr omega = q0.conjugate() * q1; //darboux vector
Quaternionr omega_plus;
omega_plus.coeffs() = omega.coeffs() + restDarbouxVector.coeffs(); //delta Omega with -Omega_0
omega.coeffs() = omega.coeffs() - restDarbouxVector.coeffs(); //delta Omega with + omega_0
if (omega.squaredNorm() > omega_plus.squaredNorm()) omega = omega_plus;
for (int i = 0; i < 3; i++) omega.coeffs()[i] *= bendingAndTwistingKs[i] / (invMassq0 + invMassq1 + static_cast<Real>(1.0e-6));
omega.w() = 0.0; //discrete Darboux vector does not have vanishing scalar part
corrq0 = q1 * omega;
corrq1 = q0 * omega;
corrq0.coeffs() *= invMassq0;
corrq1.coeffs() *= -invMassq1;
return true;
}
// ----------------------------------------------------------------------------------------------
bool PositionBasedElasticRods::solve_PerpendiculaBisectorConstraint(
const Vector3r &p0, Real invMass0,
const Vector3r &p1, Real invMass1,
const Vector3r &p2, Real invMass2,
const Real stiffness,
Vector3r &corr0, Vector3r &corr1, Vector3r &corr2)
{
const Vector3r pm = 0.5 * (p0 + p1);
const Vector3r p0p2 = p0 - p2;
const Vector3r p2p1 = p2 - p1;
const Vector3r p1p0 = p1 - p0;
const Vector3r p2pm = p2 - pm;
Real wSum = invMass0 * p0p2.squaredNorm() + invMass1 * p2p1.squaredNorm() + invMass2 * p1p0.squaredNorm();
if (wSum < eps)
return false;
const Real lambda = stiffness * p2pm.dot(p1p0) / wSum;
corr0 = -invMass0 * lambda * p0p2;
corr1 = -invMass1 * lambda * p2p1;
corr2 = -invMass2 * lambda * p1p0;
return true;
}
// ----------------------------------------------------------------------------------------------
bool PositionBasedElasticRods::solve_GhostPointEdgeDistanceConstraint(
const Vector3r& p0, Real invMass0,
const Vector3r& p1, Real invMass1,
const Vector3r& p2, Real invMass2,
const Real stiffness,
const Real ghostEdgeRestLength,
Vector3r& corr0, Vector3r& corr1, Vector3r& corr2)
{
// Ghost-Edge constraint
Vector3r pm = 0.5 * (p0 + p1);
Vector3r p2pm = p2 - pm;
Real wSum = static_cast<Real>(0.25) * invMass0 + static_cast<Real>(0.25) * invMass1 + static_cast<Real>(1.0) * invMass2;
if (wSum < eps)
return false;
Real p2pm_mag = p2pm.norm();
p2pm *= static_cast<Real>(1.0) / p2pm_mag;
const Real lambda = stiffness * (p2pm_mag - ghostEdgeRestLength) / wSum;
corr0 = 0.5 * invMass0 * lambda * p2pm;
corr1 = 0.5 * invMass1 * lambda * p2pm;
corr2 = -1.0 * invMass2 * lambda * p2pm;
return true;
}
// ----------------------------------------------------------------------------------------------
bool PositionBasedElasticRods::solve_DarbouxVectorConstraint(
const Vector3r& p0, Real invMass0,
const Vector3r& p1, Real invMass1,
const Vector3r& p2, Real invMass2,
const Vector3r& p3, Real invMass3,
const Vector3r& p4, Real invMass4,
const Vector3r& bendingAndTwistingKs,
const Real midEdgeLength,
const Vector3r& restDarbouxVector,
Vector3r& corr0, Vector3r& corr1, Vector3r& corr2, Vector3r& corr3, Vector3r& corr4)
{
// Single rod element:
// 3 4 //ghost points
// | |
// --0---1---2-- // rod points
Vector3r darboux_vector;
Matrix3r d0, d1;
PositionBasedElasticRods::computeMaterialFrame(p0, p1, p3, d0);
PositionBasedElasticRods::computeMaterialFrame(p1, p2, p4, d1);
PositionBasedElasticRods::computeDarbouxVector(d0, d1, midEdgeLength, darboux_vector);
Matrix3r dajpi[3][3];
computeMaterialFrameDerivative(p0, p1, p3, d0,
dajpi[0][0], dajpi[0][1], dajpi[0][2],
dajpi[1][0], dajpi[1][1], dajpi[1][2],
dajpi[2][0], dajpi[2][1], dajpi[2][2]);
Matrix3r dbjpi[3][3];
computeMaterialFrameDerivative(p1, p2, p4, d1,
dbjpi[0][0], dbjpi[0][1], dbjpi[0][2],
dbjpi[1][0], dbjpi[1][1], dbjpi[1][2],
dbjpi[2][0], dbjpi[2][1], dbjpi[2][2]);
Matrix3r constraint_jacobian[5];
computeDarbouxGradient(
darboux_vector, midEdgeLength, d0, d1,
dajpi, dbjpi,
//bendingAndTwistingKs,
constraint_jacobian[0],
constraint_jacobian[1],
constraint_jacobian[2],
constraint_jacobian[3],
constraint_jacobian[4]);
const Vector3r constraint_value(bendingAndTwistingKs[0] * (darboux_vector[0] - restDarbouxVector[0]),
bendingAndTwistingKs[1] * (darboux_vector[1] - restDarbouxVector[1]),
bendingAndTwistingKs[2] * (darboux_vector[2] - restDarbouxVector[2]));
Matrix3r factor_matrix;
factor_matrix.setZero();
Matrix3r tmp_mat;
Real invMasses[]{ invMass0, invMass1, invMass2, invMass3, invMass4 };
for (int i = 0; i < 5; ++i)
{
tmp_mat = constraint_jacobian[i].transpose() * constraint_jacobian[i];
tmp_mat.col(0) *= invMasses[i];
tmp_mat.col(1) *= invMasses[i];
tmp_mat.col(2) *= invMasses[i];
factor_matrix += tmp_mat;
}
Vector3r dp[5];
tmp_mat = factor_matrix.inverse();
for (int i = 0; i < 5; ++i)
{
constraint_jacobian[i].col(0) *= invMasses[i];
constraint_jacobian[i].col(1) *= invMasses[i];
constraint_jacobian[i].col(2) *= invMasses[i];
dp[i] = -(constraint_jacobian[i]) * (tmp_mat * constraint_value);
}
corr0 = dp[0];
corr1 = dp[1];
corr2 = dp[2];
corr3 = dp[3];
corr4 = dp[4];
return true;
}
// ----------------------------------------------------------------------------------------------
bool PositionBasedElasticRods::computeMaterialFrame(
const Vector3r& p0,
const Vector3r& p1,
const Vector3r& p2,
Matrix3r& frame)
{
frame.col(2) = (p1 - p0);
frame.col(2).normalize();
frame.col(1) = (frame.col(2).cross(p2 - p0));
frame.col(1).normalize();
frame.col(0) = frame.col(1).cross(frame.col(2));
return true;
}
// ----------------------------------------------------------------------------------------------
bool PositionBasedElasticRods::computeDarbouxVector(const Matrix3r& dA, const Matrix3r& dB, const Real mid_edge_length, Vector3r& darboux_vector)
{
Real factor = static_cast<Real>(1.0) + dA.col(0).dot(dB.col(0)) + dA.col(1).dot(dB.col(1)) + dA.col(2).dot(dB.col(2));
factor = static_cast<Real>(2.0) / (mid_edge_length * factor);
for (int c = 0; c < 3; ++c)
{
const int i = permutation[c][0];
const int j = permutation[c][1];
const int k = permutation[c][2];
darboux_vector[i] = dA.col(j).dot(dB.col(k)) - dA.col(k).dot(dB.col(j));
}
darboux_vector *= factor;
return true;
}
// ----------------------------------------------------------------------------------------------
bool PositionBasedElasticRods::computeMaterialFrameDerivative(
const Vector3r& p0, const Vector3r& p1, const Vector3r& p2, const Matrix3r& d,
Matrix3r& d1p0, Matrix3r& d1p1, Matrix3r& d1p2,
Matrix3r& d2p0, Matrix3r& d2p1, Matrix3r& d2p2,
Matrix3r& d3p0, Matrix3r& d3p1, Matrix3r& d3p2)
{
//////////////////////////////////////////////////////////////////////////
// d3pi
//////////////////////////////////////////////////////////////////////////
const Vector3r p01 = p1 - p0;
Real length_p01 = p01.norm();
d3p0.col(0) = d.col(2)[0] * d.col(2);
d3p0.col(1) = d.col(2)[1] * d.col(2);
d3p0.col(2) = d.col(2)[2] * d.col(2);
d3p0.col(0)[0] -= 1.0;
d3p0.col(1)[1] -= 1.0;
d3p0.col(2)[2] -= 1.0;
d3p0.col(0) *= (static_cast<Real>(1.0) / length_p01);
d3p0.col(1) *= (static_cast<Real>(1.0) / length_p01);
d3p0.col(2) *= (static_cast<Real>(1.0) / length_p01);
d3p1.col(0) = -d3p0.col(0);
d3p1.col(1) = -d3p0.col(1);
d3p1.col(2) = -d3p0.col(2);
d3p2.col(0).setZero();
d3p2.col(1).setZero();
d3p2.col(2).setZero();
//////////////////////////////////////////////////////////////////////////
// d2pi
//////////////////////////////////////////////////////////////////////////
const Vector3r p02 = p2 - p0;
const Vector3r p01_cross_p02 = p01.cross(p02);
const Real length_cross = p01_cross_p02.norm();
Matrix3r mat;
mat.col(0) = d.col(1)[0] * d.col(1);
mat.col(1) = d.col(1)[1] * d.col(1);
mat.col(2) = d.col(1)[2] * d.col(1);
mat.col(0)[0] -= 1.0;
mat.col(1)[1] -= 1.0;
mat.col(2)[2] -= 1.0;
mat.col(0) *= (-static_cast<Real>(1.0) / length_cross);
mat.col(1) *= (-static_cast<Real>(1.0) / length_cross);
mat.col(2) *= (-static_cast<Real>(1.0) / length_cross);
Matrix3r product_matrix;
MathFunctions::crossProductMatrix(p2 - p1, product_matrix);
d2p0 = mat * product_matrix;
MathFunctions::crossProductMatrix(p0 - p2, product_matrix);
d2p1 = mat * product_matrix;
MathFunctions::crossProductMatrix(p1 - p0, product_matrix);
d2p2 = mat * product_matrix;
//////////////////////////////////////////////////////////////////////////
// d1pi
//////////////////////////////////////////////////////////////////////////
Matrix3r product_mat_d3;
Matrix3r product_mat_d2;
MathFunctions::crossProductMatrix(d.col(2), product_mat_d3);
MathFunctions::crossProductMatrix(d.col(1), product_mat_d2);
d1p0 = product_mat_d2 * d3p0 - product_mat_d3 * d2p0;
d1p1 = product_mat_d2 * d3p1 - product_mat_d3 * d2p1;
d1p2 = -product_mat_d3 * d2p2;
return true;
}
// ----------------------------------------------------------------------------------------------
bool PositionBasedElasticRods::computeDarbouxGradient(
const Vector3r& darboux_vector, const Real length,
const Matrix3r& da, const Matrix3r& db,
const Matrix3r dajpi[3][3], const Matrix3r dbjpi[3][3],
//const Vector3r& bendAndTwistKs,
Matrix3r& omega_pa, Matrix3r& omega_pb, Matrix3r& omega_pc, Matrix3r& omega_pd, Matrix3r& omega_pe
)
{
Real X = static_cast<Real>(1.0) + da.col(0).dot(db.col(0)) + da.col(1).dot(db.col(1)) + da.col(2).dot(db.col(2));
X = static_cast<Real>(2.0) / (length * X);
for (int c = 0; c < 3; ++c)
{
const int i = permutation[c][0];
const int j = permutation[c][1];
const int k = permutation[c][2];
// pa
{
Vector3r term1(0,0,0);
Vector3r term2(0,0,0);
Vector3r tmp(0,0,0);
// first term
term1 = dajpi[j][0].transpose() * db.col(k);
tmp = dajpi[k][0].transpose() * db.col(j);
term1 = term1 - tmp;
// second term
for (int n = 0; n < 3; ++n)
{
tmp = dajpi[n][0].transpose() * db.col(n);
term2 = term2 + tmp;
}
omega_pa.col(i) = X * (term1-(0.5 * darboux_vector[i] * length) * term2);
//omega_pa.col(i) *= bendAndTwistKs[i];
}
// pb
{
Vector3r term1(0, 0, 0);
Vector3r term2(0, 0, 0);
Vector3r tmp(0, 0, 0);
// first term
term1 = dajpi[j][1].transpose() * db.col(k);
tmp = dajpi[k][1].transpose() * db.col(j);
term1 = term1 - tmp;
// third term
tmp = dbjpi[j][0].transpose() * da.col(k);
term1 = term1 - tmp;
tmp = dbjpi[k][0].transpose() * da.col(j);
term1 = term1 + tmp;
// second term
for (int n = 0; n < 3; ++n)
{
tmp = dajpi[n][1].transpose() * db.col(n);
term2 = term2 + tmp;
tmp = dbjpi[n][0].transpose() * da.col(n);
term2 = term2 + tmp;
}
omega_pb.col(i) = X * (term1-(0.5 * darboux_vector[i] * length) * term2);
//omega_pb.col(i) *= bendAndTwistKs[i];
}
// pc
{
Vector3r term1(0, 0, 0);
Vector3r term2(0, 0, 0);
Vector3r tmp(0, 0, 0);
// first term
term1 = dbjpi[j][1].transpose() * da.col(k);
tmp = dbjpi[k][1].transpose() * da.col(j);
term1 = term1 - tmp;
// second term
for (int n = 0; n < 3; ++n)
{
tmp = dbjpi[n][1].transpose() * da.col(n);
term2 = term2 + tmp;
}
omega_pc.col(i) = -X*(term1+(0.5 * darboux_vector[i] * length) * term2);
//omega_pc.col(i) *= bendAndTwistKs[i];
}
// pd
{
Vector3r term1(0, 0, 0);
Vector3r term2(0, 0, 0);
Vector3r tmp(0, 0, 0);
// first term
term1 = dajpi[j][2].transpose() * db.col(k);
tmp = dajpi[k][2].transpose() * db.col(j);
term1 = term1 - tmp;
// second term
for (int n = 0; n < 3; ++n) {
tmp = dajpi[n][2].transpose() * db.col(n);
term2 = term2 + tmp;
}
omega_pd.col(i) = X*(term1-(0.5 * darboux_vector[i] * length) * term2);
//omega_pd.col(i) *= bendAndTwistKs[i];
}
// pe
{
Vector3r term1(0, 0, 0);
Vector3r term2(0, 0, 0);
Vector3r tmp(0, 0, 0);
// first term
term1 = dbjpi[j][2].transpose() * da.col(k);
tmp = dbjpi[k][2].transpose() * da.col(j);
term1 -= tmp;
// second term
for (int n = 0; n < 3; ++n)
{
tmp = dbjpi[n][2].transpose() * da.col(n);
term2 += tmp;
}
omega_pe.col(i) = -X*(term1+(0.5 * darboux_vector[i] * length) * term2);
//omega_pe.col(i) *= bendAndTwistKs[i];
}
}
return true;
}
// ----------------------------------------------------------------------------------------------
void PBD::DirectPositionBasedSolverForStiffRods::initLists(int numberOfIntervals, std::list <Node*> * &forward, std::list <Node*> * &backward, Node* &root)
{
if (forward != NULL)
delete[] forward;
if (backward != NULL)
delete[] backward;
if (root != NULL)
delete[] root;
forward = new std::list<Node*>[numberOfIntervals];
backward = new std::list<Node*>[numberOfIntervals];
root = new Node[numberOfIntervals];
}
bool PBD::DirectPositionBasedSolverForStiffRods::isSegmentInInterval(RodSegment *segment, int intervalIndex, Interval* intervals, std::vector<RodConstraint*> &rodConstraints, std::vector<RodSegment*> &rodSegments)
{
for (int i = intervals[intervalIndex].start; i <= intervals[intervalIndex].end; i++)
{
if ((segment == rodSegments[rodConstraints[i]->segmentIndex(0)])
|| (segment == rodSegments[rodConstraints[i]->segmentIndex(1)]))
return true;
}
return false;
}
bool PBD::DirectPositionBasedSolverForStiffRods::isConstraintInInterval(RodConstraint *constraint, int intervalIndex, Interval* intervals, std::vector<RodConstraint*> &rodConstraints)
{
for (int i = intervals[intervalIndex].start; i <= intervals[intervalIndex].end; i++)
{
if (constraint == rodConstraints[i])
return true;
}
return false;
}
void PBD::DirectPositionBasedSolverForStiffRods::initSegmentNode(Node *n, int intervalIndex, std::vector<RodConstraint*> &rodConstraints, std::vector<RodSegment*> &rodSegments, std::vector <RodConstraint*> &markedConstraints, Interval* intervals)
{
RodSegment *segment =
(RodSegment*)n->object;
std::vector<RodConstraint*> constraints;
std::vector<int> constraintIndices;
for (int j = 0; j < static_cast<int>(rodConstraints.size()); ++j)
{
RodConstraint* constraint(rodConstraints[j]);
if (rodSegments[constraint->segmentIndex(0)] == segment
|| rodSegments[constraint->segmentIndex(1)] == segment)
{
constraints.push_back(constraint);
constraintIndices.push_back(j);
}
}
for (unsigned int i = 0; i < constraints.size(); i++)
{
if (!isConstraintInInterval(constraints[i], intervalIndex, intervals, rodConstraints))
continue;
// Test whether the edge has been visited before
bool marked = false;
for (unsigned int j = 0; j < markedConstraints.size(); j++)
{
if (constraints[i] == markedConstraints[j])
{
marked = true;
break;
}
}
if (!marked)
{
Node *constraintNode = new Node();
constraintNode->index = constraintIndices[i];
constraintNode->object = constraints[i];
constraintNode->isconstraint = true;
constraintNode->parent = n;
constraintNode->D.setZero();
constraintNode->Dinv.setZero();
constraintNode->J.setZero();
constraintNode->soln.setZero();
n->children.push_back(constraintNode);
Node *segmentNode = new Node();
segmentNode->isconstraint = false;
segmentNode->parent = constraintNode;
// get other segment connected to constraint for new node
if (rodSegments[constraints[i]->segmentIndex(0)] == segment)
{
segmentNode->object = rodSegments[constraints[i]->segmentIndex(1)];
segmentNode->index = constraints[i]->segmentIndex(1);
}
else
{
segmentNode->object = rodSegments[constraints[i]->segmentIndex(0)];
segmentNode->index = constraints[i]->segmentIndex(0);
}
segmentNode->D.setZero();
segmentNode->Dinv.setZero();
segmentNode->J.setZero();
segmentNode->soln.setZero();
constraintNode->children.push_back(segmentNode);
// mark constraint
markedConstraints.push_back(constraints[i]);
initSegmentNode(segmentNode, intervalIndex, rodConstraints,
rodSegments, markedConstraints, intervals);
}
}
}
void PBD::DirectPositionBasedSolverForStiffRods::orderMatrix(Node *n, int intervalIndex, std::list <Node*> * forward, std::list <Node*> * backward)
{
for (unsigned int i = 0; i < n->children.size(); i++)
orderMatrix(n->children[i], intervalIndex, forward, backward);
forward[intervalIndex].push_back(n);
backward[intervalIndex].push_front(n);
}
void PBD::DirectPositionBasedSolverForStiffRods::initNodes(int intervalIndex, std::vector<RodSegment*> &rodSegments, Node* &root, Interval* intervals, std::vector<RodConstraint*> &rodConstraints, std::list <Node*> * forward, std::list <Node*> * backward, std::vector <RodConstraint*> &markedConstraints)
{
// find root
for (int i = 0; i < (int)rodSegments.size(); i++)
{
RodSegment * rb(rodSegments[i]);
if (!isSegmentInInterval(rb, intervalIndex, intervals, rodConstraints, rodSegments))
continue;
else
{
if (root[intervalIndex].object == NULL)
{
root[intervalIndex].object = rb;
root[intervalIndex].index = i;
}
}
if (!rb->isDynamic())
{
root[intervalIndex].object = rb;
root[intervalIndex].index = i;
break;
}
}
root[intervalIndex].isconstraint = false;
root[intervalIndex].parent = NULL;
root[intervalIndex].D.setZero();
root[intervalIndex].Dinv.setZero();
root[intervalIndex].soln.setZero();
initSegmentNode(&root[intervalIndex], intervalIndex, rodConstraints,
rodSegments, markedConstraints, intervals);
orderMatrix(&root[intervalIndex], intervalIndex, forward, backward);
}
void PBD::DirectPositionBasedSolverForStiffRods::initTree(std::vector<RodConstraint*> &rodConstraints, std::vector<RodSegment*> & rodSegments, Interval* &intervals, int &numberOfIntervals, std::list <Node*> * &forward, std::list <Node*> * &backward, Node* &root)
{
numberOfIntervals = 1;
intervals = new Interval[1];
intervals[0].start = 0;
intervals[0].end = (int)rodConstraints.size() - 1;
initLists(numberOfIntervals, forward, backward, root);
std::vector <RodConstraint*> markedConstraints;
for (int i = 0; i < numberOfIntervals; i++)
{
initNodes(i, rodSegments, root, intervals, rodConstraints, forward, backward, markedConstraints);
markedConstraints.clear();
}
}
bool PBD::DirectPositionBasedSolverForStiffRods::computeDarbouxVector(const Quaternionr & q0, const Quaternionr & q1, const Real averageSegmentLength, Vector3r & darbouxVector)
{
darbouxVector = 2. / averageSegmentLength * (q0.conjugate() * q1).vec();
return true;
}
bool PBD::DirectPositionBasedSolverForStiffRods::computeBendingAndTorsionJacobians(const Quaternionr & q0, const Quaternionr & q1, const Real averageSegmentLength, Eigen::Matrix<Real, 3, 4> & jOmega0, Eigen::Matrix<Real, 3, 4> & jOmega1)
{
jOmega0 <<
-q1.w(), -q1.z(), q1.y(), q1.x(),
q1.z(), -q1.w(), -q1.x(), q1.y(),
-q1.y(), q1.x(), -q1.w(), q1.z();
jOmega1 <<
q0.w(), q0.z(), -q0.y(), -q0.x(),
-q0.z(), q0.w(), q0.x(), -q0.y(),
q0.y(), -q0.x(), q0.w(), -q0.z();
jOmega0 *= static_cast<Real>(2.0) / averageSegmentLength;
jOmega1 *= static_cast<Real>(2.0) / averageSegmentLength;
return true;
}
bool PBD::DirectPositionBasedSolverForStiffRods::computeMatrixG(const Quaternionr & q, Eigen::Matrix<Real, 4, 3> & G)
{
// w component at index 3
G <<
static_cast<Real>(0.5)*q.w(), static_cast<Real>(0.5)*q.z(), -static_cast<Real>(0.5)*q.y(),
-static_cast<Real>(0.5)*q.z(), static_cast<Real>(0.5)*q.w(), static_cast<Real>(0.5)*q.x(),
static_cast<Real>(0.5)*q.y(), -static_cast<Real>(0.5)*q.x(), static_cast<Real>(0.5)*q.w(),
-static_cast<Real>(0.5)*q.x(), -static_cast<Real>(0.5)*q.y(), -static_cast<Real>(0.5)*q.z();
return true;
}
void PBD::DirectPositionBasedSolverForStiffRods::computeMatrixK(const Vector3r &connector, const Real invMass, const Vector3r &x, const Matrix3r &inertiaInverseW, Matrix3r &K)
{
if (invMass != 0.0)
{
const Vector3r v = connector - x;
const Real a = v[0];
const Real b = v[1];
const Real c = v[2];
// J is symmetric
const Real j11 = inertiaInverseW(0, 0);
const Real j12 = inertiaInverseW(0, 1);
const Real j13 = inertiaInverseW(0, 2);
const Real j22 = inertiaInverseW(1, 1);
const Real j23 = inertiaInverseW(1, 2);
const Real j33 = inertiaInverseW(2, 2);
K(0, 0) = c*c*j22 - b*c*(j23 + j23) + b*b*j33 + invMass;
K(0, 1) = -(c*c*j12) + a*c*j23 + b*c*j13 - a*b*j33;
K(0, 2) = b*c*j12 - a*c*j22 - b*b*j13 + a*b*j23;
K(1, 0) = K(0, 1);
K(1, 1) = c*c*j11 - a*c*(j13 + j13) + a*a*j33 + invMass;
K(1, 2) = -(b*c*j11) + a*c*j12 + a*b*j13 - a*a*j23;
K(2, 0) = K(0, 2);
K(2, 1) = K(1, 2);
K(2, 2) = b*b*j11 - a*b*(j12 + j12) + a*a*j22 + invMass;
}
else
K.setZero();
}
void PBD::DirectPositionBasedSolverForStiffRods::getMassMatrix(RodSegment *segment, Matrix6r &M)
{
if (!segment->isDynamic())
{
M = Matrix6r::Identity();
return;
}
const Vector3r &inertiaLocal = segment->InertiaTensor();
Matrix3r rotationMatrix(segment->Rotation().toRotationMatrix());
Matrix3r inertia(rotationMatrix *
Eigen::DiagonalMatrix<Real, 3>(inertiaLocal) *
rotationMatrix.transpose());
Real mass = segment->Mass();
// Upper half
for (int i = 0; i < 3; i++)
for (int j = 0; j < 6; j++)
if (i == j)
M(i, j) = mass;
else
M(i, j) = 0.0;
// lower left
for (int i = 3; i < 6; i++)
for (int j = 0; j < 3; j++)
M(i, j) = 0.0;
// lower right
for (int i = 3; i < 6; i++)
for (int j = 3; j < 6; j++)
M(i, j) = inertia(i - 3, j - 3);
}
Real PBD::DirectPositionBasedSolverForStiffRods::factor(const int intervalIndex, const std::vector<RodConstraint*> &rodConstraints, std::vector<RodSegment*> & rodSegments, const Interval* &intervals, std::list <Node*> * forward, std::list <Node*> * backward, std::vector<Vector6r> & RHS, std::vector<Vector6r> & lambdaSums, std::vector<std::vector<Matrix3r>> & bendingAndTorsionJacobians)
{
Real maxError(0.);
// compute right hand side of linear equation system
for (size_t currentConstraintIndex = 0; currentConstraintIndex < rodConstraints.size(); ++currentConstraintIndex)
{
RodConstraint* currentConstraint = rodConstraints[currentConstraintIndex];
RodSegment* segment0 = rodSegments[currentConstraint->segmentIndex(0)];
RodSegment* segment1 = rodSegments[currentConstraint->segmentIndex(1)];
const Quaternionr &q0 = segment0->Rotation();
const Quaternionr &q1 = segment1->Rotation();
const Eigen::Matrix<Real, 3, 4, Eigen::DontAlign> &constraintInfo(currentConstraint->getConstraintInfo());
Vector6r &rhs(RHS[currentConstraintIndex]);
// Compute zero-stretch part of constraint violation
const Vector3r &connector0 = constraintInfo.col(2);
const Vector3r &connector1 = constraintInfo.col(3);
Vector3r stretchViolation = connector0 - connector1;
// compute Darboux vector (Equation (7))
Vector3r omega;
computeDarbouxVector(q0, q1, currentConstraint->getAverageSegmentLength(), omega);
// Compute bending and torsion part of constraint violation
Vector3r bendingAndTorsionViolation = omega - currentConstraint->getRestDarbouxVector();
// fill right hand side of the linear equation system
const Vector6r &lambdaSum(lambdaSums[currentConstraintIndex]);
rhs.block<3, 1>(0, 0) = -stretchViolation
- Vector3r(currentConstraint->getStretchCompliance().array() *
lambdaSum.block<3, 1>(0, 0).array());
rhs.block<3, 1>(3, 0) = -bendingAndTorsionViolation
- Vector3r(currentConstraint->getBendingAndTorsionCompliance().array() *
lambdaSum.block<3, 1>(3, 0).array());
// compute max error
for (unsigned char i(0); i < 6; ++i)
{
maxError = std::max(maxError, abs(rhs[i]));
}
// Compute a part of the Jacobian here, because the relationship
// of the first and second segment to the constraint can be determined directly
// compute G matrices
Eigen::Matrix<Real, 4, 3> G0, G1;
computeMatrixG(q0, G0);
computeMatrixG(q1, G1);
// compute stretching bending Jacobians (Equation (10) and Equation (11))
Eigen::Matrix<Real, 3, 4> jOmega0, jOmega1;
computeBendingAndTorsionJacobians(q0, q1, currentConstraint->getAverageSegmentLength(), jOmega0, jOmega1);
bendingAndTorsionJacobians[currentConstraintIndex][0] = jOmega0*G0;
bendingAndTorsionJacobians[currentConstraintIndex][1] = jOmega1*G1;
}
std::list<Node*>::iterator nodeIter;
for (nodeIter = forward[intervalIndex].begin(); nodeIter != forward[intervalIndex].end(); nodeIter++)
{
Node *node = *nodeIter;
// compute system matrix diagonal
if (node->isconstraint)
{
RodConstraint* currentConstraint = (RodConstraint*)node->object;
//insert compliance
node->D.setZero();
const Vector3r &stretchCompliance(currentConstraint->getStretchCompliance());
node->D(0, 0) -= stretchCompliance[0];
node->D(1, 1) -= stretchCompliance[1];
node->D(2, 2) -= stretchCompliance[2];
const Vector3r &bendingAndTorsionCompliance(currentConstraint->getBendingAndTorsionCompliance());
node->D(3, 3) -= bendingAndTorsionCompliance[0];
node->D(4, 4) -= bendingAndTorsionCompliance[1];
node->D(5, 5) -= bendingAndTorsionCompliance[2];
}
else
{
getMassMatrix((RodSegment*)node->object, node->D);
}
// compute Jacobian
if (node->parent != NULL)
{
if (node->isconstraint)
{
//compute J
RodConstraint *constraint = (RodConstraint*)node->object;
RodSegment *segment = (RodSegment*)node->parent->object;
Real sign = 1;
int segmentIndex = 0;
if (segment == rodSegments[constraint->segmentIndex(1)])
{
segmentIndex = 1;
sign = -1;
}
const Eigen::Matrix<Real, 3, 4, Eigen::DontAlign> &constraintInfo(constraint->getConstraintInfo());
const Vector3r r = constraintInfo.col(2 + segmentIndex) - segment->Position();
Matrix3r r_cross;
Real crossSign(-static_cast<Real>(1.0)*sign);
MathFunctions::crossProductMatrix(crossSign*r, r_cross);
Eigen::DiagonalMatrix<Real, 3> upperLeft(sign, sign, sign);
node->J.block<3, 3>(0, 0) = upperLeft;
Matrix3r lowerLeft(Matrix3r::Zero());
node->J.block<3, 3>(3, 0) = lowerLeft;
node->J.block<3, 3>(0, 3) = r_cross;
Matrix3r &lowerRight(bendingAndTorsionJacobians[node->index][segmentIndex]);
node->J.block<3, 3>(3, 3) = lowerRight;
}
else
{
//compute JT
RodConstraint *constraint = (RodConstraint*)node->parent->object;
RodSegment *segment = (RodSegment*)node->object;
Real sign = 1;
int segmentIndex = 0;
if (segment == rodSegments[constraint->segmentIndex(1)])
{
segmentIndex = 1;
sign = -1;
}
const Eigen::Matrix<Real, 3, 4, Eigen::DontAlign> &constraintInfo(constraint->getConstraintInfo());
const Vector3r r = constraintInfo.col(2 + segmentIndex) - segment->Position();
Matrix3r r_crossT;
MathFunctions::crossProductMatrix(sign*r, r_crossT);
Eigen::DiagonalMatrix<Real, 3> upperLeft(sign, sign, sign);
node->J.block<3, 3>(0, 0) = upperLeft;
node->J.block<3, 3>(3, 0) = r_crossT;
Matrix3r upperRight(Matrix3r::Zero());
node->J.block<3, 3>(0, 3) = upperRight;
Matrix3r lowerRight(bendingAndTorsionJacobians[node->parent->index][segmentIndex].transpose());
node->J.block<3, 3>(3, 3) = lowerRight;
}
}
}
for (nodeIter = forward[intervalIndex].begin(); nodeIter != forward[intervalIndex].end(); nodeIter++)
{
Node *node = *nodeIter;
std::vector <Node*> children = node->children;
for (size_t i = 0; i < children.size(); i++)
{
Matrix6r JT = (children[i]->J).transpose();
Matrix6r &D = children[i]->D;
Matrix6r &J = children[i]->J;
Matrix6r JTDJ = ((JT * D) * J);
node->D = node->D - JTDJ;
}
bool chk = false;
if (!node->isconstraint)
{
RodSegment *segment = (RodSegment*)node->object;
if (!segment->isDynamic())
{
node->Dinv.setZero();
chk = true;
}
}
node->DLDLT.compute(node->D); // result reused in solve()
if (node->parent != NULL)
{
if (!chk)
{
node->J = node->DLDLT.solve(node->J);
}
else
{
node->J.setZero();
}
}
}
return maxError;
}
bool PBD::DirectPositionBasedSolverForStiffRods::solve(int intervalIndex, std::list <Node*> * forward, std::list <Node*> * backward, std::vector<Vector6r> & RHS, std::vector<Vector6r> & lambdaSums, std::vector<Vector3r> & corr_x, std::vector<Quaternionr> & corr_q)
{
std::list<Node*>::iterator nodeIter;
for (nodeIter = forward[intervalIndex].begin(); nodeIter != forward[intervalIndex].end(); nodeIter++)
{
Node *node = *nodeIter;
if (node->isconstraint)
{
node->soln = -RHS[node->index];
}
else
{
node->soln.setZero();
}
std::vector <Node*> &children = node->children;
for (size_t i = 0; i < children.size(); ++i)
{
Matrix6r cJT = children[i]->J.transpose();
Vector6r &csoln = children[i]->soln;
Vector6r v = cJT * csoln;
node->soln = node->soln - v;
}
}
for (nodeIter = backward[intervalIndex].begin(); nodeIter != backward[intervalIndex].end(); nodeIter++)
{
Node *node = *nodeIter;
bool noZeroDinv(true);
if (!node->isconstraint)
{
RodSegment *segment = (RodSegment*)node->object;
noZeroDinv = segment->isDynamic();
}
if (noZeroDinv) // if DInv == 0 child value is 0 and node->soln is not altered
{
node->soln = node->DLDLT.solve(node->soln);
if (node->parent != NULL)
{
node->soln -= node->J * node->parent->soln;
}
}
else
{
node->soln.setZero(); // segment of node is not dynamic
}
if (node->isconstraint)
{
lambdaSums[node->index] += node->soln;
}
}
// compute position and orientation updates
for (nodeIter = forward[intervalIndex].begin(); nodeIter != forward[intervalIndex].end(); nodeIter++)
{
Node *node = *nodeIter;
if (!node->isconstraint)
{
RodSegment *segment = (RodSegment *)node->object;
if (!segment->isDynamic())
{
break;
}
const Vector6r & soln(node->soln);
Vector3r deltaXSoln = Vector3r(-soln[0], -soln[1], -soln[2]);
corr_x[node->index] = deltaXSoln;
Eigen::Matrix<Real, 4, 3> G;
computeMatrixG(segment->Rotation(), G);
Quaternionr deltaQSoln;
deltaQSoln.coeffs() = G * Vector3r(-soln[3], -soln[4], -soln[5]);
corr_q[node->index] = deltaQSoln;
}
}
return true;
}
bool PBD::DirectPositionBasedSolverForStiffRods::init_DirectPositionBasedSolverForStiffRodsConstraint(
std::vector<RodConstraint*> &rodConstraints,
std::vector<RodSegment*> & rodSegments,
Interval* &intervals,
int &numberOfIntervals,
std::list <Node*> * &forward,
std::list <Node*> * &backward,
Node* &root,
const std::vector<Vector3r> &constraintPositions,
const std::vector<Real> &averageRadii,
const std::vector<Real> &youngsModuli,
const std::vector<Real> &torsionModuli,
std::vector<Vector6r> & RHS,
std::vector<Vector6r> & lambdaSums,
std::vector<std::vector<Matrix3r>> & bendingAndTorsionJacobians,
std::vector<Vector3r> & corr_x,
std::vector<Quaternionr> & corr_q
)
{
// init constraints
for (size_t cIdx(0); cIdx < rodConstraints.size(); ++cIdx)
{
RodConstraint * constraint(rodConstraints[cIdx]);
RodSegment * segment0(rodSegments[constraint->segmentIndex(0)]);
RodSegment * segment1(rodSegments[constraint->segmentIndex(1)]);
init_StretchBendingTwistingConstraint(
segment0->Position(), segment0->Rotation(), segment1->Position(), segment1->Rotation(),
constraintPositions[cIdx], averageRadii[cIdx], constraint->getAverageSegmentLength(),
youngsModuli[cIdx], torsionModuli[cIdx], constraint->getConstraintInfo(),
constraint->getStiffnessCoefficientK(), constraint->getRestDarbouxVector());
}
// compute tree data structure for direct solver
initTree(rodConstraints, rodSegments, intervals, numberOfIntervals, forward, backward, root);
RHS.resize(rodConstraints.size());
std::fill(RHS.begin(), RHS.end(), Vector6r::Zero());
lambdaSums.resize(rodConstraints.size());
std::fill(lambdaSums.begin(), lambdaSums.end(), Vector6r::Zero());
bendingAndTorsionJacobians.resize(rodConstraints.size());
std::vector<Matrix3r> sampleJacobians(2);
sampleJacobians[0].setZero();
sampleJacobians[1].setZero();
std::fill(bendingAndTorsionJacobians.begin(), bendingAndTorsionJacobians.end(), sampleJacobians);
corr_x.resize(rodSegments.size());
std::fill(corr_x.begin(), corr_x.end(), Vector3r::Zero());
corr_q.resize(rodSegments.size());
std::fill(corr_q.begin(), corr_q.end(), Quaternionr::Identity());
return true;
}
bool PBD::DirectPositionBasedSolverForStiffRods::initBeforeProjection_DirectPositionBasedSolverForStiffRodsConstraint(
const std::vector<RodConstraint*> &rodConstraints,
const Real inverseTimeStepSize,
std::vector<Vector6r> & lambdaSums
)
{
for (size_t cIdx(0); cIdx < rodConstraints.size(); ++cIdx)
{
RodConstraint * constraint(rodConstraints[cIdx]);
initBeforeProjection_StretchBendingTwistingConstraint(
constraint->getStiffnessCoefficientK(),
inverseTimeStepSize,
constraint->getAverageSegmentLength(),
constraint->getStretchCompliance(),
constraint->getBendingAndTorsionCompliance(),
lambdaSums[cIdx]);
}
return true;
}
bool PBD::DirectPositionBasedSolverForStiffRods::update_DirectPositionBasedSolverForStiffRodsConstraint(
const std::vector<RodConstraint*> &rodConstraints,
const std::vector<RodSegment*> & rodSegments
)
{
// update rod constraints
for (size_t cIdx(0); cIdx < rodConstraints.size(); ++cIdx)
{
RodConstraint * constraint(rodConstraints[cIdx]);
RodSegment * segment0(rodSegments[constraint->segmentIndex(0)]);
RodSegment * segment1(rodSegments[constraint->segmentIndex(1)]);
update_StretchBendingTwistingConstraint(
segment0->Position(), segment0->Rotation(), segment1->Position(), segment1->Rotation(),
constraint->getConstraintInfo());
}
return true;
}
bool PBD::DirectPositionBasedSolverForStiffRods::solve_DirectPositionBasedSolverForStiffRodsConstraint(
const std::vector<RodConstraint*> &rodConstraints,
std::vector<RodSegment*> & rodSegments,
const Interval* intervals,
const int &numberOfIntervals,
std::list <Node*> * forward,
std::list <Node*> * backward,
std::vector<Vector6r> & RHS,
std::vector<Vector6r> & lambdaSums,
std::vector<std::vector<Matrix3r>> & bendingAndTorsionJacobians,
std::vector<Vector3r> & corr_x,
std::vector<Quaternionr> & corr_q
)
{
for (int i = 0; i < numberOfIntervals; i++)
{
factor(i, rodConstraints, rodSegments, intervals,
forward, backward, RHS, lambdaSums, bendingAndTorsionJacobians);
}
for (int i = 0; i < numberOfIntervals; i++)
{
solve(i, forward, backward, RHS, lambdaSums, corr_x, corr_q);
}
return true;
}
bool PBD::DirectPositionBasedSolverForStiffRods::init_StretchBendingTwistingConstraint(
const Vector3r &x0, const Quaternionr &q0,
const Vector3r &x1, const Quaternionr &q1,
const Vector3r &constraintPosition,
const Real averageRadius,
const Real averageSegmentLength,
const Real youngsModulus,
const Real torsionModulus,
Eigen::Matrix<Real, 3, 4, Eigen::DontAlign> &constraintInfo,
Vector3r &stiffnessCoefficientK,
Vector3r &restDarbouxVector
)
{
// constraintInfo contains
// 0: connector in segment 0 (local)
// 1: connector in segment 1 (local)
// 2: connector in segment 0 (global)
// 3: connector in segment 1 (global)
// transform in local coordinates
const Matrix3r rot0T = q0.matrix().transpose();
const Matrix3r rot1T = q1.matrix().transpose();
constraintInfo.col(0) = rot0T * (constraintPosition - x0);
constraintInfo.col(1) = rot1T * (constraintPosition - x1);
constraintInfo.col(2) = constraintPosition;
constraintInfo.col(3) = constraintPosition;
// compute bending and torsion stiffness of the K matrix diagonal; assumption: the rod axis follows the y-axis of the local frame as with Blender's armatures
Real secondMomentOfArea(static_cast<Real>(M_PI_4) * std::pow(averageRadius, static_cast<Real>(4.0)));
Real bendingStiffness(youngsModulus * secondMomentOfArea);
Real torsionStiffness(static_cast<Real>(2.0) * torsionModulus * secondMomentOfArea);
stiffnessCoefficientK = Vector3r(bendingStiffness, torsionStiffness, bendingStiffness);
// compute rest Darboux vector
computeDarbouxVector(q0, q1, averageSegmentLength, restDarbouxVector);
return true;
}
bool PBD::DirectPositionBasedSolverForStiffRods::initBeforeProjection_StretchBendingTwistingConstraint(
const Vector3r &stiffnessCoefficientK,
const Real inverseTimeStepSize,
const Real averageSegmentLength,
Vector3r &stretchCompliance,
Vector3r &bendingAndTorsionCompliance,
Vector6r &lambdaSum
)
{
Real inverseTSQuadratic(inverseTimeStepSize*inverseTimeStepSize);
// compute compliance parameter of the stretch constraint part
const Real stretchRegularizationParameter(static_cast<Real>(1.E-10));
stretchCompliance <<
stretchRegularizationParameter * inverseTSQuadratic,
stretchRegularizationParameter * inverseTSQuadratic,
stretchRegularizationParameter * inverseTSQuadratic;
// compute compliance parameter of the bending and torsion constraint part
bendingAndTorsionCompliance <<
inverseTSQuadratic / stiffnessCoefficientK(0),
inverseTSQuadratic / stiffnessCoefficientK(1),
inverseTSQuadratic / stiffnessCoefficientK(2);
bendingAndTorsionCompliance *= static_cast<Real>(1.0) / averageSegmentLength;
// set sum of delta lambda values to zero
lambdaSum.setZero();
return true;
}
bool PBD::DirectPositionBasedSolverForStiffRods::update_StretchBendingTwistingConstraint(
const Vector3r &x0, const Quaternionr &q0,
const Vector3r &x1, const Quaternionr &q1,
Eigen::Matrix<Real, 3, 4, Eigen::DontAlign> &constraintInfo
)
{
// constraintInfo contains
// 0: connector in segment 0 (local)
// 1: connector in segment 1 (local)
// 2: connector in segment 0 (global)
// 3: connector in segment 1 (global)
// compute world space positions of connectors
const Matrix3r rot0 = q0.matrix();
const Matrix3r rot1 = q1.matrix();
constraintInfo.col(2) = rot0 * constraintInfo.col(0) + x0;
constraintInfo.col(3) = rot1 * constraintInfo.col(1) + x1;
return true;
}
bool PBD::DirectPositionBasedSolverForStiffRods::solve_StretchBendingTwistingConstraint(
const Real invMass0,
const Vector3r &x0,
const Matrix3r &inertiaInverseW0,
const Quaternionr &q0,
const Real invMass1,
const Vector3r &x1,
const Matrix3r &inertiaInverseW1,
const Quaternionr &q1,
const Vector3r &restDarbouxVector,
const Real averageSegmentLength,
const Vector3r &stretchCompliance,
const Vector3r &bendingAndTorsionCompliance,
const Eigen::Matrix<Real, 3, 4, Eigen::DontAlign> &constraintInfo,
Vector3r &corr_x0, Quaternionr &corr_q0,
Vector3r &corr_x1, Quaternionr &corr_q1,
Vector6r &lambdaSum
)
{
// compute Darboux vector (Equation (7))
Vector3r omega;
computeDarbouxVector(q0, q1, averageSegmentLength, omega);
// compute bending and torsion Jacobians (Equation (10) and Equation (11))
Eigen::Matrix<Real, 3, 4> jOmega0, jOmega1;
computeBendingAndTorsionJacobians(q0, q1, averageSegmentLength, jOmega0, jOmega1);
// compute G matrices (Equation (27))
Eigen::Matrix<Real, 4, 3> G0, G1;
computeMatrixG(q0, G0);
computeMatrixG(q1, G1);
Matrix3r jOmegaG0(jOmega0*G0),
jOmegaG1(jOmega1*G1);
// Compute zero-stretch part of constraint violation (Equation (23))
const Vector3r &connector0 = constraintInfo.col(2);
const Vector3r &connector1 = constraintInfo.col(3);
Vector3r stretchViolation = connector0 - connector1;
// Compute bending and torsion part of constraint violation (Equation (23))
Vector3r bendingAndTorsionViolation = omega - restDarbouxVector;
// fill right hand side of the linear equation system (Equation (19))
Vector6r rhs;
rhs.block<3, 1>(0, 0) = -stretchViolation
- Vector3r(stretchCompliance.array() * lambdaSum.block<3, 1>(0, 0).array());
rhs.block<3, 1>(3, 0) = -bendingAndTorsionViolation
- Vector3r(bendingAndTorsionCompliance.array() * lambdaSum.block<3, 1>(3, 0).array());
// compute matrix of the linear equation system (using Equations (25), (26), and (28) in Equation (19))
Matrix6r JMJT(Matrix6r::Zero());
// compute stretch block
Matrix3r K1, K2;
computeMatrixK(connector0, invMass0, x0, inertiaInverseW0, K1);
computeMatrixK(connector1, invMass1, x1, inertiaInverseW1, K2);
JMJT.block<3, 3>(0, 0) = K1 + K2;
// compute coupling blocks
const Vector3r ra = connector0 - x0;
const Vector3r rb = connector1 - x1;
Matrix3r ra_crossT, rb_crossT;
MathFunctions::crossProductMatrix(-ra, ra_crossT); // use -ra to get the transpose
MathFunctions::crossProductMatrix(-rb, rb_crossT); // use -rb to get the transpose
Matrix3r offdiag(Matrix3r::Zero());
if (invMass0 != 0.0)
{
offdiag = jOmegaG0 * inertiaInverseW0 * ra_crossT * (-1);
}
if (invMass1 != 0.0)
{
offdiag += jOmegaG1 * inertiaInverseW1 * rb_crossT;
}
JMJT.block<3, 3>(3, 0) = offdiag;
JMJT.block<3, 3>(0, 3) = offdiag.transpose();
// compute bending and torsion block
Matrix3r MInvJT0(inertiaInverseW0 * jOmegaG0.transpose());
Matrix3r MInvJT1(inertiaInverseW1 * jOmegaG1.transpose());
Matrix3r JMJTOmega(Matrix3r::Zero());
if (invMass0 != 0.0)
{
JMJTOmega = jOmegaG0*MInvJT0;
}
if (invMass1 != 0.0)
{
JMJTOmega += jOmegaG1*MInvJT1;
}
JMJT.block<3, 3>(3, 3) = JMJTOmega;
// add compliance
JMJT(0, 0) += stretchCompliance(0);
JMJT(1, 1) += stretchCompliance(1);
JMJT(2, 2) += stretchCompliance(2);
JMJT(3, 3) += bendingAndTorsionCompliance(0);
JMJT(4, 4) += bendingAndTorsionCompliance(1);
JMJT(5, 5) += bendingAndTorsionCompliance(2);
// solve linear equation system (Equation 19)
auto decomposition(JMJT.ldlt());
Vector6r deltaLambda(decomposition.solve(rhs));
// update sum of delta lambda values for next Gauss-Seidel solver iteration step
lambdaSum += deltaLambda;
// compute position and orientation updates (using Equations (25), (26), and (28) in Equation (20))
Vector3r deltaLambdaStretch(deltaLambda.block<3, 1>(0, 0)),
deltaLambdaBendingAndTorsion(deltaLambda.block<3, 1>(3, 0));
corr_x0.setZero();
corr_x1.setZero();
corr_q0.coeffs().setZero();
corr_q1.coeffs().setZero();
if (invMass0 != 0.)
{
corr_x0 += invMass0 * deltaLambdaStretch;
corr_q0.coeffs() += G0 * (inertiaInverseW0 * ra_crossT * (-1 * deltaLambdaStretch) +
MInvJT0 * deltaLambdaBendingAndTorsion);
}
if (invMass1 != 0.)
{
corr_x1 -= invMass1 * deltaLambdaStretch;
corr_q1.coeffs() += G1 * (inertiaInverseW1 * rb_crossT * deltaLambdaStretch +
MInvJT1 * deltaLambdaBendingAndTorsion);
}
return true;
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/fantasyvr/position-based-dynamic-GPU.git
git@gitee.com:fantasyvr/position-based-dynamic-GPU.git
fantasyvr
position-based-dynamic-GPU
position-based-dynamic-GPU
master

搜索帮助