这个是在Box2d-Lite代码中看到的用法,用分离轴算法(SAT)求两个Box的碰撞信息那边用到了。
Collide.cpp
int Collide(Contact* contacts, Body* bodyA, Body* bodyB) { // Setup Vec2 hA = 0.5f * bodyA->width; Vec2 hB = 0.5f * bodyB->width; Vec2 posA = bodyA->position; Vec2 posB = bodyB->position; Mat22 RotA(bodyA->rotation), RotB(bodyB->rotation); //localToWorld Mat22 RotAT = RotA.Transpose(); //转置矩阵(等于逆矩阵), worldToLocal_A Vec2 dp = posB - posA; //中心连线向量 Vec2 dA = RotAT * dp; Mat22 C = RotAT * RotB; Mat22 absC = Abs(C); // Box A faces Vec2 faceA = Abs(dA) - hA - absC * hB; if (faceA.x > 0.0f || faceA.y > 0.0f) return 0; //...... }
先给出结论:absC * hB可以用来求Box_B相对A模型空间坐标轴的AABB包围盒的halfSize大小。
下面再来验证这个结论。
先验证:abs(RotA) * hA可以用来求Box_A相对世界坐标轴的AABB包围盒的hafSize大小
1) Box_A的大小为(2, 2),旋转角度5,在(0, 0)处
a1) A的旋转矩阵为:
可以看到:矩阵的第1列和图中模型空间的x轴向量相同,第2列和图中模型空间的y轴向量相同;这个矩阵可以用来做localToWorld转换
a2) A的旋转矩阵的转置矩阵为(红色和蓝色标出的换了下位置):
矩阵第1行和模型空间的x轴向量相同,第2行和模型空间的y轴向量相同;这个矩阵可以用来做worldToLocal转换
b1) 现在将Box_A内的一个local点(1, 1)和(-1, 1)转换为世界坐标:即将他们投影到世界坐标轴上
b2) 对RotA取绝对值之后再转换local点(1, 1)
可以得到:
所以p3公式的值的意义是什么?
p3.x值:左上角顶点在世界坐标x轴上的投影,沿着y轴做翻转
p3.y值:右上角顶点在世界坐标y轴上的投影
把包围盒补完整,就能很清楚的看出上面那个就是包围盒的halfSize大小
所以,abs(旋转矩阵)的意义:
1) 把旋转角度限制在[0, 90]范围内(即:rotation%90),因为这个范围内cos和sin值都是正值
2) 旋转角度在[0, 90]时,x轴上的最大投影值肯定是abs(左上角在x轴上的投影值),y轴上的最大投影值肯定是右上角在y轴上的投影值
验证最开始的结论
2) Box_B的大小为(1, 1),旋转角度15,在(0, 0)处
a) B的旋转矩阵和转置矩阵分别为
b1) 现在将Box_B内的一个local点(0.5, 0.5)和(-0.5, 0.5)转换为Box_A内的local坐标:即将他们投影到A模型空间的坐标轴上
b2) 对C取绝对值之后再转换local点(0.5, 0.5)
可以得到:
因为这次是点的转换是:B_local -> World -> A_local,所以:
p7.x值:左上角顶点在A模型空间坐标x轴上的投影,沿着A模型空间y轴做翻转
p7.y值:右上角顶点在A模型空间坐标y轴上的投影
Box_B相对A模型空间坐标轴的AABB包围盒