OBB包围盒及其碰撞检测算法(一)

之前对于游戏的物理 引擎挺感兴趣,但是碰撞算法得学习一下,AABB就不说了,给点思路基本都能做出来,但是OBB就不一样了,涉及到了一些数学知识,其实涉及到图形方面的时候,线性代数就会常用一些,虽然这个OBB病没有涉及到图形的变换,但是也用到了线性代数的东西。

如果不懂AABB和OBB是什么的话我在这里简单说一下,玩游戏的时候,游戏中的元素会发生碰撞,有的时候元素的形状不是很规则,如果直接对不规则元素进行彭专检测更麻烦并且效率低下,所以就有了一个近似的算法,就是在物体外侧加上包围盒,什么叫包围盒,如图。


蓝色部分是不规则物体,外面的一圈方框就是包围盒,将整个物体近似看成一个矩形,这样虽然不精确,但是计算速度快,游戏基本都会用这样检测的办法,这样能让游戏运行的快,我们并不希望一个很小的游戏也要很高的配置来运行。包围盒也分好多种,这里主要介绍OBB,但是为了知道什么OBB,我要用AABB来对比一下

这个是OBB包围盒


这个是AABB包围盒


我们不难发现这两种包围盒的区别AABB的包围盒不会旋转,当物体旋转的时候,空白空间被纳入包围盒的面积更大了,这样就导致不准了。

AABB包围盒的生成也 比较容易,下面我们来看一下OBB包围盒是如何生成的,

先弄一些点,生成包围盒也就是将一些点都圈在一个方框内,有这个几个点

A(2,6) B(3,2) C(4,4) D(6,3) E(7,5);
根据这几个点做包围盒,原则就是包围盒尽可能的贴近所有点,要是AABB就好做了,去上下左右最大最小的坐标生成一个矩形就可以。但是OBB就不一样了,这里涉及到了一个叫做协方差矩阵的东西。
协方差这个词我的印象是在概率论里面听过的,协方差是什么,我说不太准确,我理解大概意思就是,有两组或者多组数据,当要比较这些数据的相关性时,发现数据的维数过多(维数就是数据项),导致比较起来困难,这时有了协方差,通过计算每组之间的协方差,这就有了一个比较参数,如果协方差是0,那就说明数据之间无关,如果不为0就是相关。大概就是这个意思,而我们计算OBB包围盒,就是要先求出这些点组成矩形的中心点,利用协方差矩阵来求,协方差矩阵大概就是这些点在一起组成相关性后的一个相关性的矩阵,个人这么理解的。这些点会有个共同的趋向。协方差矩阵就是来度量各个维度偏离其均值的程度.比如计算一个人的食量和性格开朗之间有什么关系。

这个公式来计算协方差。

这是成立 关系
协方差矩阵如下。

计算协方差矩阵不是什么问题,重要的是,我们要对角化矩阵,求出特征向量和特征值,利用特征向量来得出OBB的坐标轴

求出了坐标轴,根据已知点就可以求出OBB坐标轴中心坐标,和矩形的长宽,之后就可以确定OBB包围盒了。

这个是之前那几个点在坐标系里的分布,我们要在这里根据这些点画出OBB包围盒。这些点就相当于一个不规则形状内所包含所有的点。
先求出这些点的协方差矩阵


就是这个矩阵。这只是一个协方差矩阵,我们还要得到它的特征值和特征向量。如果手工算的话,比较好说了,要用电脑程序算,你可以用MATLAB来算,我用MATLAB得出的结果

但是我们也不能就这么直接拿MATLAB算,本着造轮子的想法就需要我们动手自己写一个函数在算。计算用的算法就是雅克比计算矩阵特征向量算法,先贴一个运行效果图,下一篇讲一下这个算法。

上面的矩阵是特征,下面的是特征向量,matlab的d是特征向量,v是特征值
  • 13
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
OBB(Oriented Bounding Box,有向包围)是一种用于包围物体的几何形状,它既能够保持物体的形状,又能够提供方便的碰撞检测和投影。以下是使用C++实现OBB包围算法的基本步骤: 1. 进行物体的三维建模,并获得每个顶点的位置信息。 2. 找到物体的最小和最大点,以确定物体的中心点。 3. 对于每个顶点,将其与物体中心点的位置向量相减,将这个向量存储在一个数组中。 4. 计算出物体的协方差矩阵,使用数组中的向量作为输入。 5. 对协方差矩阵进行特征值分解,以获得物体的主方向和大小。 6. 构建OBB包围的八个顶点,通过将物体中心点与主方向上的最小和最大边界点分别相加和相减得到。 以下是一个简单的C++代码示例,用于计算OBB包围的8个顶点: ```cpp #include <iostream> #include <vector> #include <Eigen/Dense> using namespace Eigen; void computeOBB(const std::vector<Vector3f>& points, Matrix3f& axes, Vector3f& center, Vector3f& extents) { int numPoints = points.size(); // Compute the center point of the object center.setZero(); for (int i = 0; i < numPoints; ++i) center += points[i]; center /= numPoints; // Compute the covariance matrix of the object Matrix3f covMat; covMat.setZero(); for (int i = 0; i < numPoints; ++i) { Vector3f v = points[i] - center; covMat += v * v.transpose(); } covMat /= numPoints; // Compute the eigenvalues and eigenvectors of the covariance matrix SelfAdjointEigenSolver<Matrix3f> eig(covMat); Vector3f eigenValues = eig.eigenvalues().real(); Matrix3f eigenVectors = eig.eigenvectors().real(); // Set the axes and extents of the OBB axes = eigenVectors.transpose(); extents = eigenValues.sqrt(); // Compute the 8 corners of the OBB std::vector<Vector3f> corners(8); for (int i = 0; i < 8; ++i) { Vector3f corner; for (int j = 0; j < 3; ++j) corner(j) = (i & (1 << j)) ? extents(j) : -extents(j); corners[i] = center + axes * corner; } } ``` 这个函数的输入是一个三维点的向量数组,表示物体的顶点位置。函数输出物体的OBB包围的8个顶点,以及旋转矩阵和大小向量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值