在我的程序中,我需要计算旋转的框和球体之间的碰撞以及2个旋转的框之间的碰撞。我似乎无法找到任何有关它的信息,并试图用我自己的数字来计算数字令人难以置信。
我有2个盒子和一个球体和一个盒子碰撞,但现在我需要考虑角度。到目前为止,这是我的代码:
class Box
{
public:
Box();
private:
float m_CenterX, m_CenterY, m_CenterZ, m_Width, m_Height, m_Depth;
float m_XRotation, m_YRotation, m_ZRotation;
};
class Sphere
{
public:
Sphere();
private:
float m_CenterX, m_CenterY, m_CenterZ, radius;
unsigned char m_Colour[3];
};
bool BoxBoxCollision(BoxA, BoxB)
{
//The sides of the Cubes
float leftA, leftB;
float rightA, rightB;
float topA, topB;
float bottomA, bottomB;
float nearA, nearB;
float farA, farB;
//center pivot is at the center of the object
leftA = A.GetCenterX() - A.GetWidth();
rightA = A.GetCenterX() + A.GetWidth();
topA = A.GetCenterY() - A.GetHeight();
bottomA = A.GetCenterY() + A.GetHeight();
farA = A.GetCenterZ() - A.GetDepth();
nearA = A.GetCenterZ() + A.GetDepth();
leftB = B.GetCenterX() - B.GetWidth();
rightB = B.GetCenterX() + B.GetWidth();
topB = B.GetCenterY() - B.GetHeight();
bottomB = B.GetCenterY() + B.GetHeight();
farB = B.GetCenterZ() - B.GetDepth();
nearB = B.GetCenterZ() + B.GetDepth();
//If any of the sides from A are outside of B
if( bottomA <= topB ) { return false; }
if( topA >= bottomB ) { return false; }
if( rightA <= leftB ) { return false; }
if( leftA >= rightB ) { return false; }
if( nearA <= farB ) { return false; }
if( farA >= nearB ) { return false; }
//If none of the sides from A are outside B
return true;
}
bool SphereBoxCollision( Sphere& sphere, Box& box)
{
float sphereXDistance = abs(sphere.getCenterX() - box.GetCenterX());
float sphereYDistance = abs(sphere.getCenterY() - box.GetCenterY());
float sphereZDistance = abs(sphere.getCenterZ() - box.GetCenterZ());
if (sphereXDistance >= (box.GetWidth() + sphere.getRadius())) { return false; }
if (sphereYDistance >= (box.GetHeight() + sphere.getRadius())) { return false; }
if (sphereZDistance >= (box.GetDepth() + sphere.getRadius())) { return false; }
if (sphereXDistance < (box.GetWidth())) { return true; }
if (sphereYDistance < (box.GetHeight())) { return true; }
if (sphereZDistance < (box.GetDepth())) { return true; }
float cornerDistance_sq = ((sphereXDistance - box.GetWidth()) * (sphereXDistance - box.GetWidth())) +
((sphereYDistance - box.GetHeight()) * (sphereYDistance - box.GetHeight()) +
((sphereYDistance - box.GetDepth()) * (sphereYDistance - box.GetDepth())));
return (cornerDistance_sq < (sphere.getRadius()*sphere.getRadius()));
}
如何考虑轮换?任何建议都会很棒。
答案 0 :(得分:1)
首先,你的对象是盒子,而不是矩形。术语矩形严格保留用于2D图形。
当您处理旋转时,通常应将它们视为affine transform的特殊形式。仿射变换可以是旋转,平移,缩放操作,剪切操作或这些的任意组合,并且它可以由简单的4x4矩阵表示,该矩阵乘以给出框的顶点的向量。也就是说,您可以将任何旋转的,缩放的剪切框描述为已应用仿射变换的单位框(向量&lt; 0,0,0&gt;到&lt; 1,1,1&gt;之间的框)。
大多数仿射变换的矩阵(除了那些按零因子缩放的矩阵)可以被反转,这样你就可以将任何一点转换成盒子的坐标系,然后将它与&lt; 0,0进行比较, 0 GT;和&lt; 1,1,1&gt;检查它是否在框内,并将框的坐标中的任何点转换回您的世界坐标系(例如,您可以通过变换矢量&lt; 0.5,0.5,0.5&gt;来找到框的中心)。由于任何直线在应用仿射变换时都保持直线,因此您需要变换的只是框的顶点。
现在,您可以只取一个框的顶点(&lt; 0,0,0&gt;,&lt; 0,0,1&gt;,...),将它们转换为您的世界坐标系,然后将它们转换回来进入另一个盒子的坐标系。之后,两个框是否重叠的问题成为变换的八个顶点描述的框是否与单元框重叠的问题。现在,您可以轻松确定单位框(y > 0
)的基准平面上方,顶部平面(y < 1
)下方是否存在顶点,依此类推。不幸的是,有很多情况需要覆盖盒子/盒子的交叉点,与诸如盒子之类的复杂物体相比,它更容易与球体,光线,平面等相交。但是,将一个盒子固定在单元盒上会有很大的帮助。
旁注:
对于3D中的旋转,知道如何使用quaternions是值得的。 Euler angles和类似系统都存在gimbal lock问题,四元数没有此限制。
基本上,每个单位四元数描述围绕单个自由轴的旋转。当您将两个单位四元数相乘时,您将得到第三个四元数,它为您提供一个接一个地应用两个四元数所产生的旋转。并且,由于计算四元数的乘法逆是微不足道的,因此您还可以将一个四元数除以另一个四元数,以回答您需要应用于从一个旋转状态到另一个旋转状态的单轴旋转的问题。就欧拉角而言,最后一部分根本不可能做到。四元数确实是数学中最甜蜜的部分之一。
我根本无法涵盖这个答案中的所有细节,这个话题相当广泛而有趣。这就是我将四篇维基百科文章联系起来的原因。如果您需要更多详细信息,请阅读它们。
答案 1 :(得分:0)
对于Box-Box碰撞,以第一个框在原点居中并与轴对齐的方式变换坐标。然后检查第二个盒子是否与它碰撞更容易,即使这不是很简单。对于大多数情况(物理引擎在小dt * v,你可以假设运动是连续的),它足以检查是否有任何顶点落在第一个框内。
Box-Sphere更简单。像以前一样,变换坐标的方式使得框在原点居中并与轴对齐。现在,您只需要检查盒子中心与每个规范平面(由轴生成)之间的距离是否小于球体的半径加上法线方向上盒子跨度的一半。