Box2D-Lite源码阅读笔记(5)

0.简介

前一篇对碰撞检测的准备工作做了阅读,这回我们看第一步,分离轴定理检测矩形是否相交。

1.分离轴定理

这里面简单对分离轴定理做一个说明,这个里面有详细说明分离轴定理详细说明

大概就是比如两个凸多边形,这两个多边形分别向每条边的垂直方向做投影,如果有一个方向上的投影不相交,则两个多边形不相交,反之则相交。

具体就看上面的链接吧。

2.代码阅读

int Collide(Contact* contacts, Body* bodyA, Body* bodyB)
{

    ...    

    //C是一个从B坐标系变换到A坐标系的一个矩阵
	Mat22 C = RotAT * RotB;
	//经过Abs处理,Abs实际就是将矩阵中每个元素都进行求绝对值
	//最后absC中全部都是大于等于0的数字
	Mat22 absC = Abs(C);
	//这里将absC矩阵转置得到逆矩阵
	Mat22 absCT = absC.Transpose();

	//1.分离轴计算碰撞
	// Box A faces
	Vec2 faceA = Abs(dA) - hA - absC * hB;
  	if (faceA.x > 0.0f || faceA.y > 0.0f)
		return 0;

	// Box B faces
	Vec2 faceB = Abs(dB) - absCT * hA - hB;
	if (faceB.x > 0.0f || faceB.y > 0.0f)
		return 0;

    ...
}

上面这段代码,其中,这里就是计算出一个矩阵C,求其绝对值和其逆。

//C是一个从B坐标系变换到A坐标系的一个矩阵
Mat22 C = RotAT * RotB;
//经过Abs处理,Abs实际就是将矩阵中每个元素都进行求绝对值
//最后absC中全部都是大于等于0的数字
Mat22 absC = Abs(C);
//这里将absC矩阵转置得到逆矩阵
Mat22 absCT = absC.Transpose();

如何判断是否相交?

上图是只做A物体分离轴投影的结果,当然物体B也应该做一次,这里没有画出,还是画一下吧。

这回是四个轴的投影相交情况,不难看出四个轴方向只有三个方向没有相交,实际上,只要有一个不相交两个形状就不相交。我们需要得到的就是这四个轴投影的信息,或者说这四个轴投影的重叠情况。上面的四个情况都是在世界坐标下的效果,实际计算的时候,我们需要将其转换到每个矩形的局部坐标系下算。

我们拿四个情况中的以A物体x轴方向为例(上四个图中的第二个小图)。

上图中的a和b点是矩形上的点,分别投影在直线L上,a与b的选择是A最右边的点a和B最左边的点b,这样能两个点是两个矩形上x方向最接近的点,其在L上的投影点a_{1},b_{1}与各自的中心点o_{1},o_{2}连线相交与不相交就是两个矩形在x轴方向上的相交结果(根据相似原理),上图中两条红色实线并没有相交。

上面的图是在A物体局部坐标系中表示的,那么o_{1}的坐标就是(0,0),实际上寻找b点比较容易,因为就是矩形A的最右上角的点,但是寻找a点则不容易,矩形B什么姿态是不固定的,因为在A的局部坐标下,所以A的姿态是确定的,始终都是与坐标轴对齐的,但是矩形B中怎么能确定出a点呢,矩形B的x方向最左边的点,你可能会说,把矩形B的四个点遍历一遍就OK了,这样好吗,这不好。因为四个点都要与变换矩阵相乘一次,并且还要再找到哪个点符合要求,而实际上,只需要一个点与变换矩阵相乘就够了,而这一个点我们也有办法直接求出,不是遍历获得。我们将问题转换到如何找到点c,因为由对称性可知,线段ao_{2}与线段o_{2}c的长度是一样的,求出点c也可以解决问题,而点c就是矩形B中x坐标最大的点。同理y轴方向也需要找到y最大的那个点,或者说是找到y最大的那个点的y坐标值。

一个二维旋转矩阵\begin{pmatrix} cos(\theta ) & -sin(\theta )\\ sin(\theta ) & cos(\theta ) \end{pmatrix},这个矩阵乘以向量(点)后就会得到空间变换后的向量(点)。矩形有四个点坐标其从一到四象限的符号为(+,+),(+,-),(-,-),(-,+)。当矩阵乘以一个点的时候,例如\begin{pmatrix} cos(\theta ) & -sin(\theta )\\ sin(\theta ) & cos(\theta ) \end{pmatrix}*\binom{x}{y},变换后的x的结果应该为x*cos(\theta )-y*sin(\theta )

上图是sin与cos的函数图像,图中标出了sin(x),cos(x),在不同区域的正负组合,结合公式x*cos(\theta )-y*sin(\theta )来看,当确定一个\theta之后,那么sin与cos的符号已经确定,例如当\theta \in (0,\frac{\pi }{2})的时候,sin与cos符号为(+,+),对于矩形的四个顶点坐标,当坐标符号为(+,-)的时候,x*cos(\theta )-y*sin(\theta )的值最大,此时符号为(+,-)的点是第四象限的点,同理y坐标计算也是如此,当旋转角度变化的时候,sin与cos的符号也在变化,使得x*cos(\theta )-y*sin(\theta )结果最大的矩形顶点也随之变化,但总是四个顶点中的一个,而且哪个顶点使得结果最大取决于sin与cos的符号,这样一来,如果仅仅是获得最大值的话,那么就将矩阵\begin{pmatrix} cos(\theta ) & -sin(\theta )\\ sin(\theta ) & cos(\theta ) \end{pmatrix}的每个元素求绝对值,然后去矩形顶点坐标都为正的那个顶点,这样\begin{pmatrix} cos(\theta ) & sin(\theta )\\ sin(\theta ) & cos(\theta ) \end{pmatrix}*\binom{x}{y}得出来的结果\binom{x_{1}}{y_{1}}中的x_{1}y_{1}的值都是变换中四个顶点坐标中最大的x,y。由于得到了这个最大的x,y的结果,假设矩形A的最大x为x_{a},矩形B的最大x为x_{b},那么只需要计算x_{a}+x_{b}>length(o_{1}-o_{2})即可判断x轴方向的投影是否相交。

// Box A faces
//dA是两个矩形终点连线的向量,做了Abs运算后,dA表示的只是数值意义。
//实际上,下面的代码是Abs(dA) - (hA + absC * hB)
//hA就是矩形A右上角的点,absC * hB就是求出B点在A矩形的局部坐标系下的四个顶点中
//x,y方向上的最大值,因为dA,hA,hB都是从(0,0)点出发的向量,所以向量中的数值仅仅
//表示数值意义
//Abs(dA) - (hA + absC * hB)对于这个式子,如果只看x轴
//实际上就是dA的x坐标表示两个矩形的中心连线在x轴投影长度为s,
//hA是矩形A的x方向在中心连线的最大投影长度a,absC*hB就是矩形B的x方向在中心连线的最大投影长度b
//如果s-a-b大于0,这说明投影不相交。
Vec2 faceA = Abs(dA) - hA - absC * hB;
if (faceA.x > 0.0f || faceA.y > 0.0f)
	return 0;

// Box B faces
Vec2 faceB = Abs(dB) - absCT * hA - hB;
if (faceB.x > 0.0f || faceB.y > 0.0f)
    return 0;

 

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值