Bullet 引擎 详解 DBVT 分析

DBVT 在bullet 引擎中是很基础且重要的一个数据结构,本质上是一个可以动态更新的AABB树。在bullet的远距阶段是很高效的碰撞检测数据结构(比较OOB,K- DOP)。是组成dbvtbroadphase的重要成员。

首先看看树中节点的定义

view plaincopy to clipboardprint?
struct  btDbvtNode  
{  
    btDbvtVolume    volume;    // point to the bounding volume  
    btDbvtNode*     parent;    // point to parent node  
    DBVT_INLINE bool    isleaf() const      { return(childs[1]==0); }  
    DBVT_INLINE bool    isinternal() const  { return(!isleaf()); }  
    union 
    {  
        btDbvtNode* childs[2]; // point to child nodes if node is internal type  
        void*   data;          // point to Dbvtproxy object if node is leaf node    
        int     dataAsInt;     // padding ?   
    };  
}; 
struct btDbvtNode
{
 btDbvtVolume volume;    // point to the bounding volume
 btDbvtNode*  parent;    // point to parent node
 DBVT_INLINE bool isleaf() const  { return(childs[1]==0); }
 DBVT_INLINE bool isinternal() const { return(!isleaf()); }
 union
 {
  btDbvtNode* childs[2]; // point to child nodes if node is internal type
  void* data;          // point to Dbvtproxy object if node is leaf node 
  int  dataAsInt;     // padding ?
 };
};

很明显这是一个典型的二叉树节点,同时当node是内部节点时将指向2个子结点,node是叶子节点时,将指向用户定义数据(具体见后续分析)


--------------------------------------------------------------------------------

接下来是DBVT 的部分基础定义

view plaincopy to clipboardprint?
struct  btDbvt  
{  
    // Fields  
    btDbvtNode*     m_root;    // root node of the tree   
    btDbvtNode*     m_free;    // node buffer last one deleted  
    int             m_lkhd;    // number of look ahead  
    int             m_leaves;  // number of nodes   
    unsigned        m_opath;   // bitmap, mean the path to the node   

struct btDbvt
{
  // Fields
 btDbvtNode*  m_root;    // root node of the tree
 btDbvtNode*  m_free;    // node buffer last one deleted
 int    m_lkhd;    // number of look ahead
 int    m_leaves;  // number of nodes
 unsigned  m_opath;   // bitmap, mean the path to the node
}
 

这里的look ahead 基本没有在代码中用到。 m_opath将在优化中使用,主要用于纪录通往特定节点的路径。


--------------------------------------------------------------------------------

创建节点比较直接,唯一值得注意的就是利用到了m_free 这个最后被从树中删除的节点(节点分配内存未释放)

如果m_free仍未被释放就重复利用,节省一次malloc调用。

view plaincopy to clipboardprint?
static DBVT_INLINE btDbvtNode*  createnode( btDbvt* pdbvt,  
                                           btDbvtNode* parent,  
                                           void* data)  
{  
    btDbvtNode* node;  
    //if the node pool is avaliable  
    if(pdbvt->m_free)   
    { node=pdbvt->m_free;pdbvt->m_free=0; }  // if yes, use it and reset the pointer  
    else 
    { node=new(btAlignedAlloc(sizeof(btDbvtNode),16)) btDbvtNode(); } // otherwise alloc memory to node  
    node->parent =   parent;  // set the parent  
    node->data       =   data;    // set the data  
    node->childs[1]  =   0;       // set the right child pointer as  null  
    return(node);  

static DBVT_INLINE btDbvtNode* createnode( btDbvt* pdbvt,
             btDbvtNode* parent,
             void* data)
{
 btDbvtNode* node;
 //if the node pool is avaliable
 if(pdbvt->m_free)
 { node=pdbvt->m_free;pdbvt->m_free=0; }  // if yes, use it and reset the pointer
 else
 { node=new(btAlignedAlloc(sizeof(btDbvtNode),16)) btDbvtNode(); } // otherwise alloc memory to node
 node->parent = parent;  // set the parent
 node->data  = data;    // set the data
 node->childs[1] = 0;       // set the right child pointer as  null
 return(node);
}


--------------------------------------------------------------------------------

插入节点到树中较为复杂,主要算法是插入到树中距离被插入节点距离(曼哈顿距离)最近的节点,并且合成新的父节点,并且向上传导包围体的变化(复习一下AABB)。


 


--------------------------------------------------------------------------------

删除节点和插入节点比较类似,主要算法是用兄弟节点替换父节点,同时向上传导产生的包围体变化。

 


--------------------------------------------------------------------------------

节点排序,检查父节点和字节点对象的地址,如果父节点地址高于子节点,则交换父子节点,

view plaincopy to clipboardprint?
//make sure the parent's address is smaller than child node   
static DBVT_INLINE btDbvtNode*  sort(btDbvtNode* n,btDbvtNode*& r) // r is reference    
{  
    btDbvtNode* p=n->parent;  
    btAssert(n->isinternal());    
    if(p>n) //all idea is swap the postion betwwen p and n . if the n address is smaller than p address.  
    {  
        const int       i=indexof(n);  
        const int       j=1-i;  
        btDbvtNode* s=p->childs[j];  // get the sibling node  
        btDbvtNode* q=p->parent;     // get the grand father node  
        btAssert(n==p->childs[i]);   // confirm again!  
        if(q) q->childs[indexof(p)]=n; else r=n;  
        s->parent=n;  // reset the sibling node's parent to node  
        p->parent=n;  // reset the parent's parent  to node  
        n->parent=q;  // reset the node's parent to grand father  
        p->childs[0]=n->childs[0]; //reset  parent node' child node to node's child  
        p->childs[1]=n->childs[1]; //reset  parent node' child node to node's child  
        n->childs[0]->parent=p;    //reset  node's child node's parent node to parent  
        n->childs[1]->parent=p;    //reset  node's child node's parent node to parent  
        n->childs[i]=p;            //reset  node's child to parent node  
        n->childs[j]=s;            //reset  node's child to parent node  
        btSwap(p->volume,n->volume); //swap the volume   
        return(p);  //make sure return the greater one   
    }  
    return(n); //make sure return the greater one   

//make sure the parent's address is smaller than child node
static DBVT_INLINE btDbvtNode* sort(btDbvtNode* n,btDbvtNode*& r) // r is reference 
{
 btDbvtNode* p=n->parent;
 btAssert(n->isinternal()); 
 if(p>n) //all idea is swap the postion betwwen p and n . if the n address is smaller than p address.
 {
  const int  i=indexof(n);
  const int  j=1-i;
  btDbvtNode* s=p->childs[j];  // get the sibling node
  btDbvtNode* q=p->parent;     // get the grand father node
  btAssert(n==p->childs[i]);   // confirm again!
  if(q) q->childs[indexof(p)]=n; else r=n;
  s->parent=n;  // reset the sibling node's parent to node
  p->parent=n;  // reset the parent's parent  to node
  n->parent=q;  // reset the node's parent to grand father
  p->childs[0]=n->childs[0]; //reset  parent node' child node to node's child
  p->childs[1]=n->childs[1]; //reset  parent node' child node to node's child
  n->childs[0]->parent=p;    //reset  node's child node's parent node to parent
  n->childs[1]->parent=p;    //reset  node's child node's parent node to parent
  n->childs[i]=p;            //reset  node's child to parent node
  n->childs[j]=s;            //reset  node's child to parent node
  btSwap(p->volume,n->volume); //swap the volume
  return(p);  //make sure return the greater one
 }
 return(n); //make sure return the greater one
}

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/superwiles/archive/2010/02/18/5310655.aspx

posted @ 2011-03-02 09:15  oayx  阅读(959)  评论(0编辑  收藏  举报