简述 Bullet 中软体的碰撞检测与响应算法,仅针对 Soft 类型,Deformable 类型不包含在这篇文章中。
1. 软体碰撞检测
在 Bullet Physics 中,软体的碰撞检测采用的是 “点-面” 的方法,即分别用两个软体的 m_ndbvt
和 m_fdbvt
做碰撞检测,两个 bvh 树之间的遍历方法不在此展开,当 Node
和 Face
的包围盒发生碰撞时,便执行 CollideVF_SS::Process(...)
函数进行点和三角形的精确碰撞检测,该函数在 btSoftBodyInternals.h 文件中。
点和面的碰撞检测采用的是投影法(专业名词不确定),即计算点在三角形上的投影点(或最近点)。具体流程和思路如下:
btVector3 o = node->mx; // 假设 `Node` 点为空间原点,即在 `Node` 点处建立空间坐标系,那么,将三角形的位置减去 o,再计算空间原点到三角形的投影点(或最近点)。
btVector3 p; // 在 `Node` 空间坐标系下,原点到三角形的投影点(或最近点)
btScalar d = SIMD_INFINITY; // Node 点到投影点(最近点)的距离(的平方)
ProjectOrigin(face->m_n[0]->m_x - o,
face->m_n[1]->m_x - o,
face->m_n[2]->m_x - o,
p, d);
其中, ProjectOrign(...)
函数就是计算原点到三角形上的投影点(或最近点),并给出距离(的平方)。具体,可参见该函数。
接下来,便是判断 Node
点是否与 Face
碰撞。在这里,是根据 “边界”+“位移” 大于 “投影距离” 的方法。即,
const btScalar m = mrg + (o - node->m_q).length() * 2;
if (d < (m * m))
{ ... }
当发生碰撞后,便计算碰撞信息,具体碰撞信息如下:
btSoftBody::SContact c;
c.m_normal = p / -btSqrt(d); // 法向量,即由三角形面片指向 `Node` 点
c.m_margin = m; // 边界,是 mrg + (o - node->m_q).length() * 2
c.m_node = node;
c.m_face = face;
c.m_weights = w; // 投影点(或最近点)在三角形上的位置,采用质心坐标表示
c.m_friction = btMax(psb[0]->m_cfg.kDF, psb[1]->m_cfg.kDF);
c.m_cfm[0] = ma / ms * psb[0]->m_cfg.kSHR;
c.m_cfm[1] = mb / ms * psb[1]->m_cfg.kSHR;
软体碰撞的检测算法相对还是比较简单的。接下来,便是软体的碰撞响应。