静止接触

64 阅读1分钟

静止接触

多个刚体相互接触时,力相互影响,需要建立方程组,同时求解。

算法

刚体上一点的加速度

刚体移动x(t)x(t),旋转R(t)R(t),那么其上的一点p0p_0

p(t)=R(t)p0+x(t) p(t) = R(t)p_0+x(t)

速度:

p˙(t)=R˙(t)p0+x˙(t)=ω(t)×R(t)p0+v(t)=ω(t)×(R(t)p0+x(t)x(t))+v(t)=ω(t)×(p(t)x(t))+v(t)=ω(t)×r(t)+v(t) \begin{aligned} \dot{p}(t) &= \dot{R}(t)p_0+\dot{x}(t) \\ &= \omega(t) \times R(t)p_0+v(t) \\ &= \omega(t) \times (R(t)p_0 + x(t) - x(t))+v(t) \\ &= \omega(t) \times (p(t) - x(t))+v(t) \\ &= \omega(t) \times r(t)+v(t) \\ \end{aligned}

其中,r(t)=p(t)x(t)r(t)=p(t)-x(t)

加速度:

p¨(t)=ω˙(t)×r(t)+ω(t)×r˙(t)+v˙(t)=ω˙(t)×r(t)+ω(t)×(p˙(t)x˙(t))+v˙(t)=ω˙(t)×r(t)+ω(t)×(ω(t)×r(t)+v(t)v(t))+v˙(t)=ω˙(t)×r(t)+ω(t)×(ω(t)×r(t))+v˙(t) \begin{aligned} \ddot{p}(t) &= \dot{\omega}(t) \times r(t) + \omega(t) \times \dot{r}(t) + \dot{v}(t) \\ &= \dot{\omega}(t) \times r(t) + \omega(t) \times (\dot{p}(t)-\dot{x}(t)) + \dot{v}(t) \\ &= \dot{\omega}(t) \times r(t) + \omega(t) \times (\omega(t) \times r(t)+v(t) -v(t)) + \dot{v}(t) \\ &= \dot{\omega}(t) \times r(t) + \omega(t) \times (\omega(t) \times r(t)) + \dot{v}(t) \\ \end{aligned}

刚体上一点的角加速度

刚体上一点的角速度即刚体的角速度ω(t)\omega(t),由角动量L(t)=I(t)ω(t)L(t)=I(t)\omega(t),有:

ω(t)=I1L(t) \omega(t) = I^{-1}L(t)

角加速度:

ω˙(t)=I˙1L(t)+I1(t)L˙(t) \dot{\omega}(t) = \dot{I}^{-1}L(t) + I^{-1}(t)\dot{L}(t)

角动量的变化率等于力矩L˙(t)=τ(t)\dot{L}(t)=\tau(t),而转动惯量:

I1(t)=R(t)Ibody1R(t)T I^{-1}(t) = R(t)I^{-1}_{body}R(t)^T
I˙1(t)=R˙(t)Ibody1R(t)T+R(t)Ibody1R˙(t)T \dot{I}^{-1}(t) = \dot{R}(t)I^{-1}_{body}R(t)^T + R(t)I^{-1}_{body}\dot{R}(t)^T

因为R˙(t)=ω(t)×R(t)\dot{R}(t) = \omega(t) \times R(t),有:

R˙(t)T=(ω(t)×R(t))T=R(t)T(ω(t))T=R(t)Tω(t) \begin{aligned} \dot{R}(t)^T &= (\omega(t) \times R(t))^T \\ &= R(t)^T(\omega(t)^*)^T \\ &= -R(t)^T\omega(t)^* \\ \end{aligned}

因此:

I˙1(t)=R˙(t)Ibody1R(t)T+R(t)Ibody1R˙(t)T=ω(t)×R(t)Ibody1R(t)T+R(t)Ibody1(R(t)Tω(t))=ω(t)×I1(t)I1(t)ω(t) \begin{aligned} \dot{I}^{-1}(t) &= \dot{R}(t)I^{-1}_{body}R(t)^T + R(t)I^{-1}_{body}\dot{R}(t)^T \\ &= \omega(t) \times R(t)I^{-1}_{body}R(t)^T + R(t)I^{-1}_{body}(-R(t)^T\omega(t)^*) \\ &= \omega(t) \times I^{-1}(t) - I^{-1}(t)\omega(t)^* \end{aligned}
ω˙(t)=I˙1L(t)+I1(t)L˙(t)=(ω(t)×I1(t)I1(t)ω(t))L(t)+I1(t)L˙(t)=ω(t)×I1(t)L(t)I1(t)ω(t)L(t)+I1(t)L˙(t)=ω(t)×ω(t)I1(t)ω(t)L(t)+I1(t)L˙(t)=I1(t)ω(t)L(t)+I1(t)L˙(t)=I1(t)ω(t)×L(t)+I1(t)L˙(t)=I1(t)L(t)×ω(t)+I1(t)L˙(t)=I1(t)(L(t)×ω(t)+L˙(t)) \begin{aligned} \dot{\omega}(t) &= \dot{I}^{-1}L(t) + I^{-1}(t)\dot{L}(t) \\ &= (\omega(t) \times I^{-1}(t) - I^{-1}(t)\omega(t)^*)L(t) + I^{-1}(t)\dot{L}(t)\\ &= \omega(t) \times I^{-1}(t)L(t) - I^{-1}(t)\omega(t)^*L(t) + I^{-1}(t)\dot{L}(t)\\ &= \omega(t) \times \omega(t) - I^{-1}(t)\omega(t)^*L(t) + I^{-1}(t)\dot{L}(t) \\ &= - I^{-1}(t)\omega(t)^*L(t) + I^{-1}(t)\dot{L}(t) \\ &= - I^{-1}(t)\omega(t) \times L(t) + I^{-1}(t)\dot{L}(t) \\ &= I^{-1}(t)L(t) \times \omega(t) + I^{-1}(t)\dot{L}(t) \\ &= I^{-1}(t)(L(t) \times \omega(t) + \dot{L}(t)) \\ \end{aligned}

碰撞

tt时刻,第ii个接触点处的两个刚体aabb的距离:

di(t)=n^i(t)(pa(t)pb(t)) d_i(t) = \hat{n}_i(t) \cdot (p_a(t)-p_b(t))

要满足静止的条件,有:

di(t)=d˙i(t)=d¨i(t)=0 d_i(t) = \dot{d}_i(t) = \ddot{d}_i(t) = 0
d˙i(t)=n^˙i(t)(pa(t)pb(t))+n^i(t)(p˙a(t)p˙b(t)) \dot{d}_i(t) = \dot{\hat{n}}_i(t)\cdot (p_a(t)-p_b(t)) + \hat{n}_i(t) \cdot (\dot{p}_a(t)- \dot{p}_b(t))
d¨i(t)=n^¨(t)(pa(t)pb(t))+2n^˙i(t)(p˙a(t)p˙b(t))+n^i(t)(p¨a(t)p¨b(t)) \ddot{d}_i(t) = \ddot{\hat{n}}(t)\cdot(p_a(t)-p_b(t)) + 2\dot{\hat{n}}_i(t) \cdot (\dot{p}_a(t)- \dot{p}_b(t)) + \hat{n}_i(t) \cdot (\ddot{p}_a(t)- \ddot{p}_b(t))

因为接触di(t)=0d_i(t)=0,即pa(t)pb(t)=0p_a(t)-p_b(t)=0,所以:

d¨i(t)=2n^˙i(t)(p˙a(t)p˙b(t))+n^i(t)(p¨a(t)p¨b(t)) \ddot{d}_i(t) = 2\dot{\hat{n}}_i(t) \cdot (\dot{p}_a(t)- \dot{p}_b(t)) + \hat{n}_i(t) \cdot (\ddot{p}_a(t)- \ddot{p}_b(t))

第一项2n^˙i(t)(p˙a(t)p˙b(t))2\dot{\hat{n}}_i(t) \cdot (\dot{p}_a(t)- \dot{p}_b(t))只与速度相关。

由前面刚体上一点的加速度,有:

p¨a(t)=ω˙a(t)×ra(t)+ωa(t)×(ωa(t)×ra(t))+v˙a(t) \ddot{p}_a(t) = \dot{\omega}_a(t) \times r_a(t) + \omega_a(t) \times (\omega_a(t) \times r_a(t)) + \dot{v}_a(t) \\

jj个接触对刚体aa的于pjp_j处施加力fjn^j(t)f_j\hat{n}_j(t),则其有影响:

v˙a(t)=ma1fin^j(t) \dot{v}_a(t) = m_a^{-1}f_i\hat{n}_j(t) \\
ω˙a(t)=Ia1(t)L(t)×ωa(t)+Ia1(t)L˙a(t)=Ia1(t)La(t)×ωa(t)+Ia1(t)τa(t)=Ia1(t)La(t)×ωa(t)+Ia1(t)(pjxa(t))×fjn^j(t) \begin{aligned} \dot{\omega}_a(t) &= I_a^{-1}(t)L(t) \times \omega_a(t) + I_a^{-1}(t)\dot{L}_a(t) \\ &= I_a^{-1}(t)L_a(t) \times \omega_a(t) + I_a^{-1}(t)\tau_a(t) \\ &= I_a^{-1}(t)L_a(t) \times \omega_a(t) + I_a^{-1}(t)(p_j-x_a(t))\times f_j\hat{n}_j(t) \\ \end{aligned}

故:

p¨a(t)=[Ia1(t)La(t)×ωa(t)+Ia1(t)(pjxa(t))×fjn^j(t)]×ra(t)+ωa(t)×(ωa(t)×ra(t))+ma1fin^j(t)=fi(ma1n^j(t)+Ia1(t)(pjxa(t))×n^j(t)×ra(t))+Ia1(t)La(t)×ωa(t)×ra(t)+ωa(t)×(ωa(t)×ra(t)) \begin{aligned} \ddot{p}_a(t) &= [I_a^{-1}(t)L_a(t) \times \omega_a(t) + I_a^{-1}(t)(p_j-x_a(t))\times f_j\hat{n}_j(t)] \times r_a(t) \\ & \quad + \omega_a(t) \times (\omega_a(t) \times r_a(t)) + m_a^{-1}f_i\hat{n}_j(t) \\ &= f_i\left(m_a^{-1}\hat{n}_j(t) + I_a^{-1}(t)(p_j-x_a(t))\times \hat{n}_j(t) \times r_a(t)\right) \\ & \quad + I_a^{-1}(t)L_a(t) \times \omega_a(t) \times r_a(t) + \omega_a(t) \times (\omega_a(t) \times r_a(t)) \end{aligned}

第一项与fif_i有关,第二项无关

非接触力合力对刚体aa于第ii个接触点处有影响:

p¨aext(t)=ma1Fa(t)+Ia1(t)τa(t)×ra \ddot{p}^{ext}_a(t) = m_a^{-1}F_a(t)+ I_a^{-1}(t)\tau_a(t)\times r_a

把所有对刚体aa有影响的力产生的加速度求和:

p¨a(t)=jp¨aj(t)+p¨aext(t) \ddot{p}_a(t) = \sum_j \ddot{p}^j_a(t) + \ddot{p}^{ext}_a(t)

刚体b同理

所以整理与fif_i有关的项,和无关的项:

d¨i(t)=2n^˙i(t)(p˙a(t)p˙b(t))+n^i(t)(p¨a(t)p¨b(t))=jajfj+bi \begin{aligned} \ddot{d}_i(t) &= 2\dot{\hat{n}}_i(t) \cdot (\dot{p}_a(t)- \dot{p}_b(t)) + \hat{n}_i(t) \cdot (\ddot{p}_a(t)- \ddot{p}_b(t)) \\ &=\sum_j a_j f_j + b_i \end{aligned}

整理成矩阵的形式:

[d¨1d¨id¨m]=0 \begin{bmatrix} \ddot{d}_1 \\ \vdots \\ \ddot{d}_i \\ \vdots \\ \ddot{d}_m \\ \end{bmatrix} = 0

整理成矩阵的形式:

[a11a1mai1aimam1amm][f1fifm]=[b1bibm]Ax=b \begin{aligned} \begin{bmatrix} a_{11} & \cdots & a_{1m} \\ & \vdots & \\ a_{i1} & \cdots & a_{im} \\ & \vdots & \\ a_{m1} & \cdots & a_{mm} \\ \end{bmatrix} \begin{bmatrix}f_1 \\ \vdots \\ f_i\\ \vdots \\f_m\end{bmatrix} &= \begin{bmatrix}b_1 \\ \vdots \\ b_i\\ \vdots \\b_m\end{bmatrix} \\ \bf{A}\bf{x}&=\bf{b} \end{aligned}

其中:

bi=2n^˙i(t0)(p˙a(t0)p˙b(t0))+n^i(t0)[ma1Fa(t)+Ia1(t)τa(t)×ra+Ia1(t)La(t)×ωa(t)×ra(t)+ωa(t)×(ωa(t)×ra(t))]+n^i(t0)[mb1Fb(t)+Ib1(t)τb(t)×rb+Ib1(t)Lb(t)×ωb(t)×rb(t)+ωb(t)×(ωb(t)×rb(t))] \begin{aligned} b_i &= 2\dot{\hat{n}}_i(t_0)\cdot(\dot{p}_a(t_0) - \dot{p}_b(t_0)) \\ & \quad + \hat{n}_i(t_0)[ m_a^{-1}F_a(t)+ I_a^{-1}(t)\tau_a(t)\times r_a \\ & \quad \quad + I_a^{-1}(t)L_a(t) \times \omega_a(t) \times r_a(t) + \omega_a(t) \times (\omega_a(t) \times r_a(t)) ] \\ & \quad + \hat{n}_i(t_0)[ m_b^{-1}F_b(t)+ I_b^{-1}(t)\tau_b(t)\times r_b \\ & \quad \quad + I_b^{-1}(t)L_b(t) \times \omega_b(t) \times r_b(t) + \omega_b(t) \times (\omega_b(t) \times r_b(t)) ] \end{aligned}
aij=n^i(t0)[ma1n^j(t0)+Ia1(t0)(pjxa(t0))×n^j(t0)×ra(t0)+mb1n^j(t0)+Ib1(t)(pjxb(t0))×n^j(t0)×rb(t0)] \begin{aligned} a_{ij} &= \hat{n}_i(t_0)[m_a^{-1}\hat{n}_j(t_0) + I_a^{-1}(t_0)(p_j-x_a(t_0))\times \hat{n}_j(t_0) \times r_a(t_0) \\ & \quad + m_b^{-1}\hat{n}_j(t_0) + I_b^{-1}(t)(p_j-x_b(t_0))\times \hat{n}_j(t_0) \times r_b(t_0)] \end{aligned}

程序

计算bib_i


VectorXf ForceBasedDynamics::ComputeBVector(std::vector<Contact> &C)
{
    VectorXf B(C.size());
    B.setZero();

    for (int i = 0; i < C.size(); ++i)
    {
        Contact &c = C[i];
        Rigidbody &a = c.a_;
        Rigidbody &b = c.b_;
        Vector3f &n = c.normal_;
        Vector3f ra = c.position_ - a.GetPosition();
        Vector3f rb = c.position_ - b.GetPosition();

        /*Get the external forces and torques*/
        Vector3f f_ext_a{0.F, g, 0.F};
        Vector3f f_ext_b{0.F, g, 0.F};
        Vector3f t_ext_a{0.F, 0.F, 0.F};
        Vector3f t_ext_b{0.F, 0.F, 0.F};

        Vector3f a_ext_part, a_vel_part, b_ext_part, b_vel_part;
        a_ext_part = f_ext_a * a.GetMassInv() + ((a.GetInertiaMomentInv() * t_ext_a).cross(ra));
        b_ext_part = f_ext_b * b.GetMassInv() + ((b.GetInertiaMomentInv() * t_ext_b).cross(rb));

        if (a.GetMassInv() == 0.F)
        {
            a_vel_part = Vector3f::Zero();
        }
        else
        {
            a_vel_part = (a.GetAngularVelocity().cross(a.GetAngularVelocity().cross(ra))) +
                         ((a.GetInertiaMomentInv() *
                           (a.GetInertiaMomentInv().inverse() * a.GetAngularVelocity().cross(a.GetAngularVelocity())))
                              .cross(ra));
        }
        if (b.GetMassInv() == 0.F)
        {
            b_vel_part = Vector3f::Zero();
        }
        else
        {
            b_vel_part = (b.GetAngularVelocity().cross(b.GetAngularVelocity().cross(rb))) +
                         ((b.GetInertiaMomentInv() *
                           (b.GetInertiaMomentInv().inverse() * b.GetAngularVelocity().cross(b.GetAngularVelocity())))
                              .cross(rb));
        }
        float k1 = n.dot((a_ext_part + a_vel_part) - (b_ext_part + b_vel_part));
        Vector3f ndot = computeNdot(c);

        Vector3f pta = a.GetVelocity() + a.GetAngularVelocity().cross(ra);
        Vector3f ptb = b.GetVelocity() + b.GetAngularVelocity().cross(rb);

        float k2 = 2.f * ndot.dot(pta - ptb);
        B(i) = k1 + k2;
    }

    return B;
}

计算aija_{ij}


float compute_aij(const Contact &ci, const Contact &cj)
{
    /* If the bodies involved in the ith and jth contact are distinct, then aij is zero.*/
    if ((&ci.a_ != &cj.a_) && (&ci.a_ != &cj.b_) && (&ci.b_ != &cj.a_) && (&ci.b_ != &cj.b_))
    {
        return 0;
    }

    Rigidbody &a = ci.a_;
    Rigidbody &b = ci.b_;
    const Vector3f &ni = ci.normal_;
    const Vector3f &nj = cj.normal_;
    const Vector3f &pi = ci.position_;
    const Vector3f &pj = cj.position_;
    Vector3f ra = pi - a.GetPosition();
    Vector3f rb = pi - b.GetPosition();

    /* what force and torque does contact j exert on body a?*/
    Vector3f force_on_a = {0.F, 0.F, 0.F};
    Vector3f torque_on_a = {0.F, 0.F, 0.F};
    if (&cj.a_ == &ci.a_)
    {
        /* force direction of jth contact force on a*/
        force_on_a = nj;

        /*torque direction*/
        torque_on_a = (pj - a.GetPosition()).cross(nj);
    }
    else if (&cj.b_ == &ci.a_)
    {
        force_on_a = -nj;
        torque_on_a = (pj - a.GetPosition()).cross(-nj);
    }

    /* what force and torque does contact j exert on body b?*/
    Vector3f force_on_b = {0.F, 0.F, 0.F};
    Vector3f torque_on_b = {0.F, 0.F, 0.F};
    if (&cj.a_ == &ci.b_)
    {
        /* force direction of jth contact force on a*/
        force_on_b = nj;

        /*torque direction*/
        torque_on_b = (pj - b.GetPosition()).cross(nj);
    }
    else if (&cj.b_ == &ci.b_)
    {
        force_on_b = -nj;
        torque_on_b = (pj - b.GetPosition()).cross(-nj);
    }

    /* Now compute how the jth contact force affects the linear and angular acceleration of the contact point on body A */
    Vector3f a_linear = force_on_a * a.GetMassInv(), a_angular = (a.GetInertiaMomentInv() * torque_on_a).cross(ra);
    /* Same for B */
    Vector3f b_linear = force_on_b * b.GetMassInv(), b_angular = (b.GetInertiaMomentInv() * torque_on_b).cross(rb);
    return ni.dot((a_linear + a_angular) - (b_linear + b_angular));
}
// derivative of the normal vector
Vector3f computeNdot(const Contact &c)
{
    return c.b_.GetAngularVelocity().cross(c.normal_);
}

建构A矩阵:

Eigen::MatrixXf ForceBasedDynamics::BuildMatrix(std::vector<Contact> &C)
{
    MatrixXf M(C.size(), C.size());
    for (int i = 0; i < C.size(); ++i)
    {
        for (int j = 0; j < C.size(); ++j)
        {
            M(i, j) = compute_aij(C[i], C[j]);
            assert(!isnan(M(i, j)));
        }
    }
    return M;
}

迭代求解:

const size_t kIterateCount = 50;

Eigen::VectorXf CraneMath::solveGS(Eigen::MatrixXf M, Eigen::VectorXf b) {
  Eigen::VectorXf x(b.size());
  x.setOnes();

  int n = 0;
  while (n < kIterateCount) {
    for (int i = 0; i < b.size(); i++) {
      float delta = 0.F;
      for (int j = 0; j < b.size(); j++) {
        if (i != j) {
          delta += M(i, j) * x(j);
        }
      }

      x(i) = (b(i) - delta) / M(i, i);
    }
    n++;
  }

  return x;
}

测试

ezgif.com-video-to-gif.gif

参考

  1. Baraff D. Physically based modeling: Rigid body simulation[J]. SIGGRAPH Course Notes, ACM SIGGRAPH, 2001, 2(1): 2-1.