OBB盒的实现

本文介绍了在几何仿真中的碰撞检测,特别是OBB(oriented bounding box)的实现。OBB是一种能紧密包围对象的包围盒,其相交测试基于分离轴理论。通过计算对象在15条可能的轴上的投影来判断两个OBB是否相交。文章还提供了一个简单的OBB类实现,包括顶点、旋转、投影和相交测试等功能。
部署运行你感兴趣的模型镜像

制造几何仿真中的碰撞检测通常视为针对刚体对象间的碰撞检测,这样的话可以把非刚体即软体的建模和变形算法对碰撞检测的影响减少到最小。常见成熟的基于包围盒的碰撞检测(box intersection test)算法如:

1)沿坐标轴的包围盒AABB(axis-aligned bounding boxes)在碰撞检测的研究历史中使用得最久最广, 一个给定对象的AABB被定义为包含该对象且各边平行于坐标轴的最小的六面体。

AABB间的相交测试也比较简单,两个AABB相交当且仅当它们在三个坐标轴上的投影区间均重叠。定义AABB的六个最大最小值分别确定了它在三个坐标轴上的投影区间,因此AABB间的相交测试最多只需要六次比较运算。

2)包围球类似于AABB,也是简单性好紧密性差的一类包围盒,包围球被定义为包含该对象的最小的球体,计算给定对象E的包围球,首先需确定包围球的球心c,再由球心与三个最大值坐标所确定的点间的距离计算半径r。包围球的计算时间略多于AABB,但存储一个包围球只需两个浮点数。

3)方向包围盒OBB(oriented bounding box)是比较著名的一个包围盒类型。一个给定对象的OBB被定义为包含该对象且相对于坐标轴方向任意的最小的长方体。OBB最大特点是它的方向的任意性,这使得它可以根据被包围对象的形状特点尽可能紧密地包围对象,但同时也使得它的相交测试变得复杂。

OBB间的相交测试基于分离轴理论(separating axis test)。若两个OBB在一条轴线上(不一定是坐标轴)上的投影不重叠,则这条轴称为分离轴。若一对OBB间存在一条分离轴,则可以判定这两个OBB不相交。对任何两个不相交的凸三维多面体,其分离轴要么垂直于任何一个多面体的某一个面,要么同时垂直于每个多面体的某一条边。因此,对一对OBB,只需测试15条可能是分离轴的轴(每个OBB的3个面方向再加上每个OBB的3个边方面的两两组合),只要找到一条这样的分离轴,就可以判定这两个OBB是不相交的,如果这15条轴都不能将这两个OBB分离,则它们是相交的。 

可以在运动过程中使用OBB进行初次碰撞检测,如果没有碰撞,则忽略进行下一个检测,如果发生碰撞,则调用更精细的碰撞检测。作者定义的包围盒(bounding box)和实现如下:

 

 

 

class Point3D 
{
public:
    double x;
    double y;
    double z;
public:
    Point3D();
    Point3D(double X, double Y, double Z);
    virtual ~Point3D();
public:
    //两个向量的交叉乘积(矩阵形式)用于就法向量
    Point3D operator^(Point3D pt);叉乘cross product
    Point3D operator-(Point3D pt);
    Point3D operator+(Point3D pt);
    double operator*(Point3D pt);//点乘dot product
    Point3D operator*(double k);
    void Normalize();
    float VecMod();
};

class CboundingBox
{
public:
    CBoundingBox();
    virtual ~CBoundingBox();
    void SetBendRelation(double bendDim, double dim, double cen[3]);
    void GetBoxCenter(double cen[3]);
    void GetMinMax(double* min_x, double* min_y, double* min_z, double* max_x, double* max_y, double* max_z);
    void TranslatedBox(double xOffset,double yOffset,double zOffset);
    void RotateBox(double angle, double x, double y, double z);
    void InitBoundingBox(Point3D Vertex[8]);
    void UpdateBoundingBox(Point3D Vertex[8]);//更新包围盒
public:
    //定义8个顶点,
    Point3D m_Vertex[8];
public:
    //Jorbin edited[2/8/2008]
    int BoxIntersectTest(CBoundingBox * box);
    void GetInterval(CBoundingBox * box, Point3D axis, float &min, float &max);
    float Dot(Point3D axis, Point3D pt);
    Point3D GetFaceDir(int indexID);   //取面方向
    Point3D GetEdgeDir(int indexID); //取边方向
};

//点在该轴上投影值
float CBoundingBox::Dot(Point3D axis, Point3D pt)
{
    return (float)((axis * pt) / axis.VecMod());
}
void CBoundingBox::GetInterval(CBoundingBox * box, Point3D axis, float &min, float &max) 
{
    float value;
    min = max = Dot(axis, box->m_Vertex[0]);
    for(int i=1; i<8; i++)
    {
        value = Dot(axis, box->m_Vertex[i]);
        min = Min(min, value);
        max = Max(max, value);
    }
}

Point3D CBoundingBox::GetEdgeDir(int indexID)
{
    Point3D pt;
    Line3D tmpLine;
    switch(indexID) 
    {
        case 0://edge in parallel with x axis
            pt = tmpLine.Normalize(m_Vertex[0]), m_Vertex[1]);
            break;
        case 1://edge in parallel with y axis
            pt = tmpLine.Normalize(m_Vertex[0], m_Vertex[4]);
            break;
        case 2://edge in parallel with z axis
            pt = tmpLine.Normalize(m_Vertex[0], m_Vertex[3]);
            break;
    }
    return pt;
}
\

 

Point3D CBoundingBox::GetFaceDir(int indexID) {
    Point3D vFace;
    Plane3D tmpPlane;
    switch(indexID)
    {
        case 0://front and back
            vFace = tmpPlane.NormLine((m_Vertex[2], m_Vertex[3], m_Vertex[6]);
            break;
        case 1://left and right
            vFace = tmpPlane.NormLine((m_Vertex[1], m_Vertex[2], m_Vertex[5]);
            break;
        case 2://top and bottom
            vFace = tmpPlane.NormLine((m_Vertex[0], m_Vertex[1], m_Vertex[2]);
            break;
    }

    return vFace;
}

 

int CBoundingBox::BoxIntersectTest(CBoundingBox * box)
{
    int flag = 20;
    int i, j;
    float min1, max1, min2, max2;
    for (i=0; i<3; i++)
    {             
        GetInterval(this, this->GetFaceDir(i), min1, max1);              
        GetInterval(box, this->GetFaceDir(i), min2, max2);              
        if (max1 < min2 || max2 < min1) return 0;               
    } 
    for (i=0; i<3; i++)
    {             
        GetInterval(this, box->GetFaceDir(i), min1, max1);              
        GetInterval(box, box->GetFaceDir(i), min2, max2);              
        if (max1 < min2 || max2 < min1)    return 0;             
    }
    Point3D axis;
    for (i=0; i<3; i++)            
        for (j=0; j<3; j++) 
        {         
            axis = (this->GetEdgeDir(i)) ^ (box->GetEdgeDir(j));//cross product
            GetInterval(this, axis, min1, max1);                      
            GetInterval(box, axis, min2, max2);                      
            if (max1 < min2 || max2 < min1)    return 0;            
        }
    return flag;

 

参考文献:
魏迎梅. 虚拟环境中碰撞检测问题的研究. 工学博士学位论文. 国防科学技术大学. 2000.10
申玉斌,蔡勇,华才建. 虚拟环境中的碰撞检测技术的研究与应用. 交通与计算机.2005.1
吴强,基于OBB碰撞检测算法的研究.硕士学位论文. 郑州大学.2007
http://www.gamasutra.com/features/19991018/Gomez_1.htm
http://www.gamasutra.com/features/19991018/Gomez_2.htm
http://www.gamasutra.com/features/19991018/Gomez_5.htm

转载于:https://www.cnblogs.com/jast/p/4100362.html

您可能感兴趣的与本文相关的镜像

Dify

Dify

AI应用
Agent编排

Dify 是一款开源的大语言模型(LLM)应用开发平台,它结合了 后端即服务(Backend as a Service) 和LLMOps 的理念,让开发者能快速、高效地构建和部署生产级的生成式AI应用。 它提供了包含模型兼容支持、Prompt 编排界面、RAG 引擎、Agent 框架、工作流编排等核心技术栈,并且提供了易用的界面和API,让技术和非技术人员都能参与到AI应用的开发过程中

### 自动驾驶场景中 OBB 包围盒实现方法 在自动驾驶领域,OBB(Oriented Bounding Box)是一种重要的碰撞检测技术,能够快速判断自车轨迹与障碍物区域的交集[^1]。以下内容详细介绍了 OBB 的定义、建模以及其实现方法。 #### 3.1 OBB 的定义与建模 OBB 是一种定向包围盒,其方向可以自由旋转,从而更紧密地包裹目标对象。相比 AABB(Axis-Aligned Bounding Box),OBB 能够显著提高碰撞检测的精度,特别是在处理非轴对齐的复杂物体时[^3]。OBB 的定义基于主成分分析(PCA)技术,通过计算点云数据的协方差矩阵来确定主要方向,并以此构建包围盒的方向和大小。 #### 3.2 OBB实现步骤 以下是实现 OBB 包围盒的具体方法: - **计算点云中心**:通过计算点云数据的质心,确定 OBB 的中心位置。 - **计算协方差矩阵并分解**:根据点云数据构建协方差矩阵,并通过特征值分解获取点云的主要方向向量。 - **构造 OBB**:利用特征向量定义 OBB 的方向,并计算包围盒的边界以确保完全包含所有点云数据。 以下是一个使用 Python 和 NumPy 实现 OBB 计算的示例代码: ```python import numpy as np # 假设 points 是一个 N x 3 的点云数据数组 def compute_obb(points): # 计算点云中心 center = np.mean(points, axis=0) # 计算协方差矩阵 cov_matrix = np.cov(points.T) # 特征值分解 eigenvalues, eigenvectors = np.linalg.eig(cov_matrix) # 获取 OBB 的方向 obb_directions = eigenvectors.T # 将点云转换到 OBB 的局部坐标系 points_local = (points - center).dot(eigenvectors) # 计算 OBB 的边界 min_coords = np.min(points_local, axis=0) max_coords = np.max(points_local, axis=0) obb_size = max_coords - min_coords return center, obb_directions, obb_size # 示例点云数据 points = np.array([ [1, 2, 3], [4, 5, 6], [7, 8, 9] ], dtype=np.float32) center, directions, size = compute_obb(points) print("OBB Center:", center) print("OBB Directions:", directions) print("OBB Size:", size) ``` #### 3.3 碰撞检测原理 OBB 的碰撞检测通常基于分离轴定理(SAT)。为了判断两个 OBB 是否发生重叠,需要将 OBB 投影到若干分离轴上进行比较。如果在所有这些轴上的投影都相互重叠,则说明两个 OBB 发生了碰撞[^3]。分离轴的选择应与 OBB 的表面正交,例如 p、q、s、t 等方向。 #### 3.4 注意事项 在实现 OBB 包围盒时,需要注意以下几点: - 大规模点云数据的计算开销较高,可能需要结合降采样或其他优化技术。 - 如果目标对象发生旋转,OBB 的方向也需要随之更新,这可能会增加额外的计算成本。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值