0.简介
上一篇介绍了碰撞检测部分,这次阅读后面的碰撞点计算和最小碰撞深度计算的代码。
1.获取碰撞点和碰撞深度
碰撞后要计算出碰撞点,因为在计算运动方向,转动惯量等数据的时候需要碰撞点信息,碰撞深度是为了分离两个物体用的信息,因为物体碰撞时刻,不能正好点边接触,两个物体可能会有一些交叉,这个交叉导致碰撞点会落在形状内部,而不是边界,并且两个物体分离,运动状态信息也需要这个交叉深度来进行各种视觉效果上的平衡。
// Find best axis
Axis axis;//选定的轴
float separation;//最小分离距离
Vec2 normal;//正面的方向
//2.找最大相交的轴方向和深度
axis = FACE_A_X;//记录轴,这里是A的x轴方向的轴
//最小分离距离,分离距离的方向是从四个分离轴方向中选的
separation = faceA.x;
//如果在A的坐标系下,中心连线的x大于0,说明物体B在A的右边,那么
//就以A的x轴正方向为normal,这里了的normal在后面被认为是A矩形的"前面"
//其中RotA.col1就是矩形A坐标系的x轴正方向
normal = dA.x > 0.0f ? RotA.col1 : -RotA.col1;
//这里是两个系数,Tol我猜是tolerance,翻译为容忍
const float relativeTol = 0.95f;//相对95%
const float absoluteTol = 0.01f;//绝对1%
//faceA和faceB里存储的就是四个分离轴方向的相交深度
//在没有上面两个参数的时候,直接就与separation进行比较,
//此时就是谁大选谁,有faceA与faceB来源可知,值是负数的时候才有效,
//所以选择更大的,就是更接近与0的负数,那么其绝对值表达是就是
//两个形状的镶嵌的深度。if判断里的式子暂时不知为何这么写,估计是个经验表达式
if (faceA.y > relativeTol * separation + absoluteTol * hA.y)
{
axis = FACE_A_Y;
separation = faceA.y;
normal = dA.y > 0.0f ? RotA.col2 : -RotA.col2;
}
// Box B faces
if (faceB.x > relativeTol * separation + absoluteTol * hB.x)
{
axis = FACE_B_X;
separation = faceB.x;
normal = dB.x > 0.0f ? RotB.col1 : -RotB.col1;
}
if (faceB.y > relativeTol * separation + absoluteTol * hB.y)
{
axis = FACE_B_Y;
separation = faceB.y;
normal = dB.y > 0.0f ? RotB.col2 : -RotB.col2;
}
//3.计算碰撞的边和线段我和位置
// Setup clipping plane data based on the separating axis
Vec2 frontNormal, sideNormal;
ClipVertex incidentEdge[2];
float front, negSide, posSide;
char negEdge, posEdge;
//Compute the clipping lines and the line segment to be clipped.
switch (axis)
{
case FACE_A_X://如果是A坐标系x轴方向为最小分离距离
{
frontNormal = normal;//normal是最小分离距离方向
//posA在frontNormal上投影,此时得到的长度是x方向上的长度,加上hA.x
//得到的front表达的是"前面的"x轴方向的位置,碰撞物体的碰撞点会落在
//这个normal方向的边上。
front = Dot(posA, frontNormal) + hA.x;
sideNormal = RotA.col2;//取垂直于FACE_A_X的另一个轴
//计算两个侧面的坐标值,就是"前面"的上下位置限制,
//实际就是确定另一个轴上的矩形两边边界的世界坐标值。
float side = Dot(posA, sideNormal);
negSide = -side + hA.y;
posSide = side + hA.y;
//记录两个边是什么
negEdge = EDGE3;
posEdge = EDGE1;
//以A为正,计算B相交于A的边和相关的点
//这个函数执行后会得到两个物体的相交点,
//这个点是取自于矩形四个定向中的点,假如在矩形A坐标系下,那么取的点
//就是矩形B上的某个顶点,一般取两个。
ComputeIncidentEdge(incidentEdge, hB, posB, RotB, frontNormal);
}
break;
//后面这些都是一样的
case FACE_A_Y:
{
frontNormal = normal;
front = Dot(posA, frontNormal) + hA.y;
sideNormal = RotA.col1;
float side = Dot(posA, sideNormal);
negSide = -side + hA.x;
posSide = side + hA.x;
negEdge = EDGE2;
posEdge = EDGE4;
ComputeIncidentEdge(incidentEdge, hB, posB, RotB, frontNormal);
}
break;
case FACE_B_X:
{
frontNormal = -normal;
front = Dot(posB, frontNormal) + hB.x;
sideNormal = RotB.col2;
float side = Dot(posB, sideNormal);
negSide = -side + hB.y;
posSide = side + hB.y;
negEdge = EDGE3;
posEdge = EDGE1;
ComputeIncidentEdge(incidentEdge, hA, posA, RotA, frontNormal);
}
break;
case FACE_B_Y:
{
frontNormal = -normal;
front = Dot(posB, frontNormal) + hB.y;
sideNormal = RotB.col1;
float side = Dot(posB, sideNormal);
negSide = -side + hB.x;
posSide = side + hB.x;
negEdge = EDGE2;
posEdge = EDGE4;
ComputeIncidentEdge(incidentEdge, hA, posA, RotA, frontNormal);
}
break;
}
代码中的变量在实际中表示如下。
![](https://i-blog.csdnimg.cn/blog_migrate/fbb0dda5dcbe91dc9a0c7f9322b8daf2.jpeg)
front是矢量,negEdge表示的negSide是坐标值posEdge也一样,属于矢量,实际都是x或者y的坐标值。