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 车牌定位步骤 ...
随机推荐
- Java并发编程基础-ReentrantLock的机制
同步锁: 我们知道,锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源,在Lock接口出现之前,Java应用程序只能依靠synchronized关键字来实现同步锁 ...
- Mycat节点扩缩容及高可用集群方案
数据迁移与扩容实践: 工具目前从 mycat1.6,准备工作:1.mycat 所在环境安装 mysql 客户端程序. 2.mycat 的 lib 目录下添加 mysql 的 jdbc 驱动包. 3.对 ...
- 【scapy】读取pcap
scapy读取pcap包 假设有pcap包test.pcap,读取其中的分层流量信息 代码: import scapy_http.http try: import scapy.all as scapy ...
- 一张图看懂JVM之垃圾回收算法详解
导读 ...
- Vue 添加外部的时间插件不触发v-model事件更改数据
使用的jquery日期插件 最终问题是 在选择完成日期后并未激活 oninput事件,所以也没有激活v-model 去改变date 解决思路: 去插件js文件中,在赋值给dom的时候添加模拟输入事件便 ...
- web和servlet一样的用法但是有区别
- VUE,页面跳转传多个参数
<template> <a @click="goNext">Next</a> <input type="text" v ...
- vscode c++ cmake template project
VSCode configure C++ dev environment claim use CMake to build the project. For debugging, VSCode's C ...
- Asp.NetCore 读取配置文件帮助类
/// <summary> /// 读取配置文件信息 /// </summary> public class ConfigExtensions { public static ...
- Faster-RCNN tensorflow 程序细节
tf-faster-rcnn github:https://github.com/endernewton/tf-faster-rcnn backbone,例如vgg,conv层不改变feature大小 ...