2D Rotated Rectangle Collision
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的更多相关文章
- “等一下,我碰!”——常见的2D碰撞检测
转自:https://aotu.io/notes/2017/02/16/2d-collision-detection/ 在 2D 环境下,常见的碰撞检测方法如下: 外接图形判别法 轴对称包围盒(Axi ...
- Emgu-WPF学习使用-Rectangle识别
原文:Emgu-WPF学习使用-Rectangle识别 环境:Win8 64位 Vs2015 Emgu 版本:emgucv-windesktop 3.2.0.2682 示例图上部流程:原图->灰 ...
- opencv6.5-imgproc图像处理模块之轮廓
接opencv6.4-imgproc图像处理模块之直方图与模板 这部分的<opencv_tutorial>上都是直接上代码,没有原理部分的解释的. 十一.轮廓 1.图像中找轮廓 /// 转 ...
- 【IOS笔记】Views
Views Because view objects are the main way your application interacts with the user, they have many ...
- OpenCV学习笔记四:ImgProc模块
一,简介 这个模块包含一系列的常用图像处理算法. 二,分析 此模块包含的文件如下图: 其导出算法包括如下: /*********************** Background statistics ...
- View Programming Guide for iOS ---- iOS 视图编程指南(四)---Views
Views Because view objects are the main way your application interacts with the user, they have many ...
- OpenCV计算机视觉学习(8)——图像轮廓处理(轮廓绘制,轮廓检索,轮廓填充,轮廓近似)
如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 1, ...
- [第四篇] PostGIS:“我让PG更完美!”
概要 本篇文章主要分为几何图形处理函数.仿生变换函数.聚类函数.边界分析函数.线性参考函数.轨迹函数.SFCGAL 函数.版本函数这八部分. Geometry Processing ST_Buffer ...
- EasyPR--开发详解(4)形态学操作、尺寸验证、旋转等操作
在上一篇深度分析与调优讨论中,我们介绍了高斯模糊,灰度化和Sobel算子.在本文中,会分析剩余的定位步骤. 根据前文的内容,车牌定位的功能还剩下如下的步骤,见下图中未涂灰的部分. 图1 车牌定位步骤 ...
随机推荐
- ubuntu 调整分辨率
修改 /etc/X11/xorg.conf配置文件即可
- git push -u 用法
在我们第一次提交git的时候: 发现上面用了这个-u参数,也没作解释,特意搜索了下这个-u的用法,加了参数-u后,以后即可直接用git push 代替git push origin master gi ...
- 爬取文件时,对已经操作过的URL进行过滤
爬取文件时,对已经操作过的URL进行过滤 1.创建过滤规则文件filter.py在spiders同级目录 class RepeatUrl: def __init__(self): self.visit ...
- SVG 图像入门教程
http://www.ruanyifeng.com/blog/2018/08/svg.html 一.概述 SVG 是一种基于 XML 语法的图像格式,全称是可缩放矢量图(Scalable Vector ...
- TagCanvas 插件
TagCanvas是一个基于HTML5 Canvas技术开发的标签云动画.还提供一个以jQuery插件形式实现的版本. 它支持文本和图片两种格式,能够以Sphere, hcylinder 或 vcyl ...
- C#学习-索引器
当一个类包含数组成员时,索引器的使用将大大地简化对类中数组成员的访问. 索引器的定义类似于属性,也具有get访问器和set访问器,以下是 [修饰符] 数据类型 this [索引类型index] { g ...
- [转] HTML5 Blob与ArrayBuffer、TypeArray和字符串String之间转换
1.将String字符串转换成Blob对象 //将字符串 转换成 Blob 对象 var blob = new Blob(["Hello World!"], { type: 'te ...
- 常用js正则表达式大全
常用js正则表达式大全.一.校验数字的js正则表达式 1 数字:^[0-9]*$ 2 n位的数字:^\d{n}$ 3 至少n位的数字:^\d{n,}$ 4 m-n位的数字:^\d{m,n}$ 5 零和 ...
- EntityFramework 优化建议(转)
转载地址:http://blog.jd-in.com/947.html Entity Framework目前最新版本是6.1.3,当然Entity Framework 7 目前还是预览版,并不能投入正 ...
- python基础——list和tuple(列表和元组)
1.list的定义,插入insert,append,按位置索引. >>> name = ['Macal','lily','lucy','bob'] --初始化>>> ...