上次说了接触计算中的几种不同的包围盒子,有限元基础知识:接触计算中的包围盒子
下面开始分别讲一下各自的编码实现,先从最简单的AABB开始,AABB包围盒由于每个面(3D)都与坐标系平行,所以其实只需要找到,x,y,z 三个方向上所有节点的最大值和最小值就行了。
下边以C++代码为例,给大家示范一下AABB的计算流程
// 函数定义
using point3D = std::array<double, 3>;
struct AABB
{
point3D min;
point3D max;
void init();
void addPoint(const point3D & p)
};
void AABB::init()
{
min[0] = min[1] = min[2] = FLT_MAX;
max[0] = max[1] = max[2] = -FLT_MAX;
};
void addPoint(const point3D & p)
{
if (p[0] < min[0]) min[0] = p[0];
if (p[0] > max[0]) max[0] = p[0];
if (p[1] < min[1]) min[1] = p[1];
if (p[1] > max[1]) max[1] = p[1];
if (p[2] < min[2]) min[2] = p[2];
if (p[2] > max[2]) max[2] = p[2];
};
// 真正的形成一个AABB
AABB box;
box.init();
// 对于主面或者从面的节点循环
// points is a vector of point3D
for (auto p : points)
{
box.addPoint(p);
}
那么这样一个主面或者从面的包围盒子就形成了,然而在真实的有限元计算中,由于我们需要定位潜在可能发生的接触,或者接触已经发生了,已经有了微小的穿透,以上还需要进行一点点补充,就是增加一些buffer,给现在的box扩大一圈,一般的做法如下:
void AABB::addBuffer(double dis)
{
min[0] -= dis;
min[1] -= dis;
min[2] -= dis;
max[0] += dis;
max[1] += dis;
max[2] += dis;
};
box.addBuffer(dis);
这样我们就完成了一个扩大化的bounding box, 如下图所示,蓝色的就是最开始计算的box,而红色虚线就是加上了buffer的box
那么然后就是如何检测两个bounding box 是否接触了,这个也非常简单,若所有轴均重叠则碰撞,否则就不
bool AABBIntersect(const AABB & box1, const AABB & box2)
{
return (box1.min[0] <= box2.max[0] && box1.max[0] >= box2.min[0]) &&
(box1.min[1] <= box2.max[1] && box1.max[1] >= box2.min[1]) &&
(box1.min[2] <= box2.max[2] && box.max[2] >= box2.min[2]);
}
这样我们就能检测两个AABB的box是否接触,做一个粗放式的检查。
好了今天就先到这,明天讲一下OBB与分离轴定理SAT的编码实现,敬请期待。