BirdCage

关于BVH的介绍可以参考
https://blog.csdn.net/StevenZhai0504/article/details/28420195

在这里参考代码
https://github.com/sglab/OpenCCD.git
这里实现我实现的是一个模仿这个的碰撞检测加速的BVH。因为布料的性质,往往碰撞的情况会出现在相邻的位置(这里可以想象自己身上的衣服?),因此在划分的时候可以简单的采用距离的划分,然后我这里建立的是一块方形的布所以做的是一个‘田’的划分。
而在原文中,进行划分的依据是AABB包围盒哪个轴比较长。对于长轴进行划分(好像是,没有看的非常仔细)

类的定义

class BVH_Node {
public:
    bool isleaf;            //判断是不是叶节点
    Vec3d minBox, maxBox;   //确定包围盒
    int node[3];            //如果是叶节点,记录对应的三个点的index
    BVH_Node *_leftChild;   //对于非叶节点记录左右子节点
    BVH_Node *_rightChild;

public:
    //非叶节点的初始化
    BVH_Node(int startX, int startY, int endX, int endY);
    //叶节点的初始化
    BVH_Node(int index1, int index2, int index3);

    ~BVH_Node();
    //重新计算包围盒
    void refit();

    /* CCD     */
    //非叶节点的碰撞检测
    void collide(BVH_Node *target);
    //叶节点的碰撞检测
    bool leafCollide(BVH_Node *target);
    //内部的碰撞检测
    void selfCollide();

    bool isLeaf() { return isleaf; };
    //判断包围盒是否相交
    bool overlaps(BVH_Node *box);
};

BVH建立

BVH_Node::BVH_Node(int startX, int startY, int endX, int endY) :isleaf(false)
{
    node[0] = -1;
    node[1] = -1;
    node[2] = -1;

    if (endX - startX == 1 && endY - startY == 1)
    {
        //将1*1的正方形块划分成两个三角形
        _leftChild = new BVH_Node(XYtoIndex(startX, startY), XYtoIndex(startX + 1, startY), XYtoIndex(startX, startY + 1));
        _rightChild = new BVH_Node(XYtoIndex(startX + 1, startY), XYtoIndex(startX, startY + 1),
            XYtoIndex(startX + 1, startY + 1));
        return;
    }

    // 对于X、Y按长轴剖分
    if (endX - startX > endY - startY)
    {
        int middleX = (startX + endX) / 2;
        _leftChild = new BVH_Node(startX, startY, middleX, endY);
        _rightChild = new BVH_Node(middleX, startY, endX, endY);
        return;
    }
    else
    {
        int middleY = (startY + endY) / 2;
        _leftChild = new BVH_Node(startX, startY, endX, middleY);
        _rightChild = new BVH_Node(startX, middleY, endX, endY);
        return;
    }

    assert(!"should not get there");
    return;

}


BVH_Node::BVH_Node(int index1, int index2, int index3) :isleaf(true)
{
    _leftChild = NULL;
    _rightChild = NULL;
    node[0] = index1;
    node[1] = index2;
    node[2] = index3;
}


BVH_Node::~BVH_Node()
{
    if (!isleaf) {
        delete _leftChild;
        delete _rightChild;
    }
}

包围盒重新计算

每次物体运动后,需要重新计算包围盒。



void BVH_Node::refit()
{
    if (isLeaf()) {
        minmax(glmToVec3d(node[0]), glmToVec3d(node[1]), glmToVec3d(node[2]),
            newVec3d(node[0]), newVec3d(node[1]), newVec3d(node[2]),
            minBox, maxBox);
        return;
    }

    _leftChild->refit();
    _rightChild->refit();
    minmax(_leftChild->minBox, _leftChild->maxBox, _rightChild->minBox, _rightChild->maxBox, minBox, maxBox);

};

碰撞检测

这里需要重新计算碰撞


/* CCD     */
void BVH_Node::selfCollide()
{
    if (isLeaf())
        return;

    _leftChild->collide(_rightChild);
    _leftChild->selfCollide();
    _rightChild->selfCollide();

};


void BVH_Node::collide(BVH_Node *target)
{

    if (overlaps(target)) {
        if (isLeaf()) {
            leafCollide(target);
            return;
        }
        else {
            _leftChild->collide(target);
            _rightChild->collide(target);
        }
    }
};



bool BVH_Node::leafCollide(BVH_Node *target)
{
    bool ret = false;
    if (target->isLeaf()) {
        //这里省略对于两个叶结点碰撞检测的代码
        //如果是三角形需要3+3次点的碰撞和3*3次边和边的碰撞

    }
    else {
        if (overlaps(target->_leftChild))
            ret |= leafCollide(target->_leftChild);
        if (overlaps(target->_rightChild))
            ret |= leafCollide(target->_rightChild);
    }


    return ret;

};



bool BVH_Node::overlaps(BVH_Node *box)
{
    if (minBox[0] - box->maxBox[0] >= ERROR_BOUND) return false;    // x
    if (minBox[1] - box->maxBox[1] >= ERROR_BOUND) return false;    // y
    if (minBox[2] - box->maxBox[2] >= ERROR_BOUND) return false;    // z

    if (ERROR_BOUND <= box->minBox[0] - maxBox[0]) return false;
    if (ERROR_BOUND <= box->minBox[1] - maxBox[1]) return false;
    if (ERROR_BOUND <= box->minBox[2] - maxBox[2]) return false;

    return true;

}

分类:

技术点:

相关文章: