Introduction

While working on a project for school, I found it necessary to perform a collision check between sprites that had been translated and rotated. I wanted to use bounding boxes because a per-pixel check was time consuming and unnecessary. After a couple of days of research I managed to work out an efficient solution using the separating axis theorem. After explaining my method to classmates and a few lab technicians, I realized that the game development community could benefit from a clear and thorough explanation of the process. Knowledge of linear algebra, specifically vector math, is useful but not necessary for understanding this article.

Separating Axis Theorem

The separating axis theorem states that for a pair of convex polygons that are not in a state of collision there exists an axis perpendicular to an edge of one of the polygons that has no overlap between the projected vertices of the two polygons. Essentially, what this means is that if we project the vertices of the two polygons that we are testing onto each axis that is perpendicular to the edges of each polygon and we detect an overlap on each polygon there is a collision, if even one axis shows no overlap then a collision is impossible. This solution works for any collision possibility, even the dreaded cross collision.  Figure 1. Cross Collision

Setting Up

Before we dive into the collision algorithm itself, there are a few prerequisites for this particular method. Firstly, although the separating axis theorem can be used to check for collisions between any convex polygons, rectangles are the normal collision method in 2D, so I will assume that you are using rectangles. Additionally, I will assume that you can convert your rectangles into a structure with four vectors, each representing a corner, and labeled or organized in such a way that you can tell which corner is which (specifically, we need to be able to identify which corners are adjacent - if the upper-left corner has been rotated until it is on the bottom of the rectangle that's fine, just so long as it remains connected by an edge to the corners labeled upper-right and lower-left.).

The Method

The problem with checking for collision between two rotated rectangles is really a matter of being able to decide when they're not colliding. The simple intersection test used by the Microsoft InteresectRect() function will check if the minimum and maximum x and y values of rectangle B are within the minimum and maximum x and y values of rectangle A. This method works fine for axis-aligned rectangles, but when dealing with rotated rectangles we need something a little more complex.  Figure 2. Standard Bounds-based Collision Check As you can see, the minimum x value of B lies within the space defined by the minimum and maximum x values of A. Additionally, the minimum y value of B lies within the space defined by the minimum and maximum y values of A. With simple bounds based collision detection this would register as a collision, when it clearly is not.

Step 1

The first step in this method is to determine the axes that we will be projecting our vertices onto. The separating axis theorem states that we must have an axis that is perpendicular to each of the edges of our two polygons.  Figure 3. The Eight Perpendicular Axes As you can see, we end up with eight axes. You should also immediately see the benefits of using rectangles. Firstly, each edge has an opposite edge which shares an identical axis, we can take advantage of this to lower the number of axes that need checked to four. Secondly, the angle that exists between any two adjacent edges on a rectangle is 90 degrees. As such, for any edge of a rectangle, both of the adjacent edges are perpendicular to it. This means that we can calculate our four axes to be as such: Axis1.x = A.UR.x - A.UL.x Axis1.y = A.UR.y - A.UL.y Axis2.x = A.UR.x - A.LR.x Axis2.y = A.UR.y - A.LR.y Axis3.x = B.UL.x - B.LL.x Axis3.y = B.UL.y - B.LL.y Axis4.x = B.UL.x - B.UR.x Axis4.y = B.UL.y - B.UR.y Meaning that Axis 1 is the resultant vector of the upper-right corner of A minus the upper-left corner of A and so on. This gives us four axes, each of which is perpendicular to two opposite edges of one of the rectangles, meaning that for each edge we have an axis that is perpendicular to it.  Figure 4. Our Four Axes

Step 2

The next step is to project the vectors representing the four corners of each rectangle onto each of the axes. If you know how to do matrix projections then you should have no problem doing this. Ifyou understand vectors, but have forgotten how to do projections, then here is the equation for the projection of rectangle A's upper-right corner onto Axis 1:  Here is the equation expanded out into scalar math and simplified:  It is important to note that the only difference between these two equations is that we're multiplying by Axis 1's x coordinate at the end of the first equation and we're multiplying by Axis 1's y coordinate at the end of the second equation. That will give you the x and y coordinates of A.UR projected onto Axis 1. As an example, let's pretend that A.UR isat location (2, 6) and Axis 1 is represented by the vector (3, 4):  Therefore, in this example, the x coordinate of A.UR projected onto Axis 1 is 3.6 and the y coordinate is 4.8.  Figure 5. Vectors Projected Onto Axis 1

Step 3

The third step in this algorithm is to calculate scalar values that will allow us to identify the maximum and minimum projected vectors for each of the rectangles. While it might seem natural to use the norm (length) of the vectors, this won't work as coordinates with negative values will return a positive scalar value. The simplest and cheapest solution is to take the dot product of each of the vectors and the axis. This will give us an essentially meaningless scalar value, however, this value will be indicative of the vector's position on the axis. To use our above example:   Figure 6. The minimum and maximum scalar values

Step 4

Now identify the maximum and minimum scalar values (the ones that we just calculated) for rectangle A and rectangle B. If the minimum scalar value of B is less than or equal to the maximum scalar value of A and the maximum scalar value of B is greater than or equal to the minimum scalar value of A then our objects overlap when projected onto this axis.

There is an error in the below image regarding Min(A). Please refer to the text above for the correct equation

  Figure 7. No Overlap = No Collision

Repeat

Repeat steps 2, 3, and 4 for each of the axes. If all of the axes show an overlap then there is a collision, if even one of the axes shows no overlap then there is no collision.

Optimizations

There are a few things that can be done to optimize this algorithm:

  • You can and should stop checking for collision the instant you find an axis where the rectangles don't overlap. Remember, the separating axis theorem says that if two polygons arecolliding all axes that are perpendicular to the edges of the polygons will show an overlap. Meaning that, if one axis shows no overlap, then collision is not possible and you should opt outto prevent unnecessary math.
  • It can really pay off to transform rectangle B into rectangle A's local space. In order to do this, you should maintain these rectangles in local space and then transform rectangle B intoworld space and then by the inverse of rectangle A's world space transform to put rectangle B into rectangle A's local space. Then, translate both rectangles equally so that rectangle Ais centered about the x and y axes. This means that two of the four axes that you need to project vectors onto are the unit (x and y) axes. Simply check for overlap between the x values of thecorners of both rectangles and between the y values of the corners of both rectangles. With this solution you only have to actually project the vectors onto arbitrary axes twice, instead of fourtimes.  Figure 8. Rectangles A and B in world space  Figure 9. Rectangles A and B Transformed Into A's Local Space
  • It can be wise to utilize a radius that completely encompasses the rectangle. If the distance between the centers of rectangles A and B is greater than the radius of A and B added together thenthere cannot possibly be a collision and it is unnecessary to use the separating axis theorem.

2D Rotated Rectangle Collision的更多相关文章

  1. “等一下,我碰!”——常见的2D碰撞检测

    转自:https://aotu.io/notes/2017/02/16/2d-collision-detection/ 在 2D 环境下,常见的碰撞检测方法如下: 外接图形判别法 轴对称包围盒(Axi ...

  2. Emgu-WPF学习使用-Rectangle识别

    原文:Emgu-WPF学习使用-Rectangle识别 环境:Win8 64位 Vs2015 Emgu 版本:emgucv-windesktop 3.2.0.2682 示例图上部流程:原图->灰 ...

  3. opencv6.5-imgproc图像处理模块之轮廓

    接opencv6.4-imgproc图像处理模块之直方图与模板 这部分的<opencv_tutorial>上都是直接上代码,没有原理部分的解释的. 十一.轮廓 1.图像中找轮廓 /// 转 ...

  4. 【IOS笔记】Views

    Views Because view objects are the main way your application interacts with the user, they have many ...

  5. OpenCV学习笔记四:ImgProc模块

    一,简介 这个模块包含一系列的常用图像处理算法. 二,分析 此模块包含的文件如下图: 其导出算法包括如下: /*********************** Background statistics ...

  6. View Programming Guide for iOS ---- iOS 视图编程指南(四)---Views

    Views Because view objects are the main way your application interacts with the user, they have many ...

  7. OpenCV计算机视觉学习(8)——图像轮廓处理(轮廓绘制,轮廓检索,轮廓填充,轮廓近似)

    如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 1, ...

  8. [第四篇] PostGIS:“我让PG更完美!”

    概要 本篇文章主要分为几何图形处理函数.仿生变换函数.聚类函数.边界分析函数.线性参考函数.轨迹函数.SFCGAL 函数.版本函数这八部分. Geometry Processing ST_Buffer ...

  9. EasyPR--开发详解(4)形态学操作、尺寸验证、旋转等操作

    在上一篇深度分析与调优讨论中,我们介绍了高斯模糊,灰度化和Sobel算子.在本文中,会分析剩余的定位步骤. 根据前文的内容,车牌定位的功能还剩下如下的步骤,见下图中未涂灰的部分. 图1 车牌定位步骤 ...

随机推荐

  1. git教程笔记(二)

    1.首先进入自己的项目文件 在GitHub上申请一个自己的账户信息.创建一个Repository.然后复制仓库的地址在gitbush中进行clone gitbush中进行远程clone 2.gitbu ...

  2. python(1):数据类型/string/list/dict/set等

    本系列文章中, python用的idle是spyder或者pycharm, 两者都很好用, spyder 是在anaconda 中的, 自带了很多包可以用, pycharm 只是个编译器, 没有很多包 ...

  3. IntersectionObserver API 使用教程

    转载:原文地址:http://www.ruanyifeng.com/blog/2016/11/intersectionobserver_api.html 网页开发时,常常需要了解某个元素是否进入了&q ...

  4. python列表1

    List (列表)List(列表) 是 Python 中使用最 频繁的数据类 型.列表 可以 完成大 多数集 合类 的数据 结构 实现. 列表中 元素 的类型 可以 不相同 ,它支 持数 字,字 符串 ...

  5. 配置frp

    一.下载 下载地址:https://github.com/fatedier/frp/releases 下载linux_amd64的,如果是32位系统就下载linux_386 二.安装 有公网IP的服务 ...

  6. ThreadPool线程池

    1.GetMaxThreads,GetMinThreads class Program { static void Main(string[] args) { int workerThreads; i ...

  7. [转] 浅析JavaScript设计模式——发布-订阅/观察者模式

    前一段时间一直在写CSS3的文章 一直都没写设计模式 今天来写写大名鼎鼎观察者模式 先画张图 观察者模式的理解 我觉得还是发布-订阅模式的叫法更容易我们理解 (不过也有的书上认为它们是两种模式……)  ...

  8. 关于sizeof与#pragma pack 以及网络上关于字节对齐的一点感想

    工作中面试中对于字节对齐基本上是必考一个知识点,而很多面试是网络上上原题.基本上背一背就可以写正确,而关于4字节对齐我相信很多人也只是一个基本地了解,对于一些题目就感觉有问题,而且很多blog后面仍然 ...

  9. H.265:网络视频的高清时代

    去年八月,爱立信公司推出了首款H.265编解码器,而在仅仅六个月之后,国际电联(ITU)就正式批准通过了HEVC/H.265标准,标准全称为高效视频编码(High Efficiency Video C ...

  10. JMeter执行压测输出HTML图形化报表(一)

    一.应用场景 1.无需交互界面或受环境限制(linux text model) 2.远程或分布式执行 3.持续集成,通过shell脚本或批处理命令均可执行,生成的测试结果可被报表生成模块直接使用,便于 ...