我想确定两个矩形是否重叠(不相交)。我知道如何对轴对齐的矩形执行此操作,但是在这种情况下,我有一个矩形并不总是与轴对齐的(也就是在其中心旋转)。 This post展示了如何计算两个相交的矩形,但不会像this picture所示那样将一个矩形内的另一个矩形分类,因为它们是重叠的,而不是相交的。
在我的情况下,一个矩形是轴对齐的(黑框),另一个是旋转的(红色框),这样可能会更容易。
我认为我需要多个案例来确定它们是否重叠。第一种简单的情况是检查黑框内是否有任何红色顶点。然后,我可以检查任何红色/黑色边缘是否相交。我不确定如何覆盖上面显示的情况以及是否有更简单的方法来做到这一点。
其他详细信息:这是针对我的图形软件裁剪器(在这种情况下,不能使用硬件裁剪),其中黑框是我的窗口/视口,红框是“ sprite”,黑框之外的所有内容都被裁剪了/未渲染我正在使用正交2D投影。最后,我将有两个功能,一个用于检测子画面是否在窗口/视口之外(我在这个问题中要问的是什么),后来我将创建一个将子画面裁剪到窗口/内的功能。 Sutherland–Hodgman算法处理视口。
编辑:
This的发布内容确实描述了如何进行SAT,但是没有具体说明。如何生成法线? “拐角”是屏幕坐标或到形状中心的距离吗?我曾尝试根据自己的目的调整其代码,但无法弄清楚如何使用每个形状/矩形的顶点列表(屏幕x和y)执行SAT测试
答案 0 :(得分:1)
这通常称为AABB-OBB相交测试。 (轴对齐的边界框和定向的边界框)。如果一个边界框完全位于另一个边界框内,则仍将其视为“相交”。
要解决此问题,请使用分隔轴定理。如果AABB和OBB不重叠,则它们必须至少有一条平行于其一侧的分离轴。
对于OBB-OBB交集测试,您将两个形状投影到8条不同的线上(每个矩形的每个边一条),并对每个投影执行简单的一维重叠测试。
对于AABB-OBB,这基本上是相同的,但是减少到4个投影,因为四对边总是平行的。
看看以下有关OBB-OBB的解释:
https://gamedev.stackexchange.com/questions/25397/obb-vs-obb-collision-detection
答案 1 :(得分:0)
首先,我要感谢用户“ prideout”为我指明了正确的方向。他的笔记,尤其是仅需要4个法线的笔记,帮助我优化了代码。奇怪的是,the link provided中的代码似乎无法正常工作(确定形状的“压碎”顶点是否重叠)。我发现this useful example in C++为我指明了正确的方向,现在我的代码运行良好。
这是我的AABB-OBB重叠检测器函数+ SAT函数(使用的语言是基于Java的“处理”)。
// True if overlap, False if they don't
boolean seperating_axis_theorem(float[] x1, float[] y1, float[] x2, float[] y2, float[] normal){
float[] range = new float[4]; //minAlong1, maxAlong1, minAlong2, maxAlong2
range[0] = Float.MAX_VALUE;
range[1] = -Float.MAX_VALUE;
range[2] = Float.MAX_VALUE;
range[3] = -Float.MAX_VALUE;
// Dot is projecting the points onto the seperating axis and then we get the max and min
float dotVal;
for(int i = 0; i < 4; i++){
dotVal = dot(x1[i], y1[i], normal[0], normal[1]);
if(dotVal < range[0]){range[0] = dotVal;}
if(dotVal > range[1]){range[1] = dotVal;}
dotVal = dot(x2[i], y2[i], normal[0], normal[1]);
if(dotVal < range[2]){range[2] = dotVal;}
if(dotVal > range[3]){range[3] = dotVal;}
}
if(range[1] < range[2] || range[0] > range[3]){
return false;
}
return true;
}
// True if two shapes overlap, False otherwise
Boolean AABB_OBB_Overlap(float[] OBB_X, float[] OBB_Y, float[] AABB_X, float[] AABB_Y){
// Checking the camera's normals, simplified since we know its axis aligned so no unit vector calculations needed
float[] range = get_range(OBB_X); // Returns min and max of array
if(range[1] < AABB_X[0] || range[0] > AABB_X[1]){
return false;
}
range = get_range(OBB_Y);
if(range[1] < AABB_Y[0] || range[0] > AABB_Y[2]){
return false;
}
// Checking the sprite's normals
float[] normal1 = unit_vector(OBB_X[1] - OBB_X[0], OBB_Y[1] - OBB_Y[0]); // Top side
float[] normal2 = unit_vector(OBB_X[2] - OBB_X[0], OBB_Y[2] - OBB_Y[0]); // Left side
if(!seperating_axis_theorem(OBB_X, OBB_Y, AABB_X, AABB_Y, normal1)){
return false;
}
if(!seperating_axis_theorem(OBB_X, OBB_Y, AABB_X, AABB_Y, normal2)){
return false;
}
// They overlap
return true;
}