旋转矩阵取绝对值的用法

发布时间 2023-12-29 00:17:45作者: yanghui01

这个是在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包围盒