Ray-AABB交叉检测算法
最近在解决三维问题时,需要判断线段是否与立方体交叉,这个问题可以引申为:射线是否穿过立方体AABB。
在3D游戏开发中碰撞检测普遍采用的算法是轴对齐矩形边界框(Axially Aligned Bounding Box, AABB)包装盒方法,其基本思想是用一个立方体或者球体完全包裹住3D物体对象,然后根据包装盒的距离、位置等相关信息来计算是否发生碰撞。
slab的碰撞检测算法
本文接下来主要讨论射线与AABB的关系,主要对box2d碰撞检测使用的slab的碰撞检测算法(Slabs method)进行介绍,然后使用python语言实现slab碰撞检测方法,该方法可以用于3D物体拾取等应用场景。
Slab英文翻译是“平板”,本文是指两个平行平面/直线之间的空间。在2D空间中slab可以理解为平行于坐标轴的两条直线间的区域,3D空间中为平行于xy平面(或者yz面,xz面)的两个平面之间的区域。由此,我们可以把3D空间中的AABB盒子看做是由AABB的3组平行面形成的3个方向的slab的交集。
另外,引入候选面的概念:在3D空间中,我们先确定正对着射线的三个面,也就是说,我们可以通过某种方式将AABB相对于射线Ray的背面给忽略掉,从而确定三个候选的面。这三个候选的面,就是有可能和射线Ray发生交叉的最近的面。
根据这个定义,我们可以得到以下三个结论:
- 性质一:如果一个点在AABB中,那么这个点必定同时在这3个slab中。
- 性质二:如果一条射线和AABB相交,那么这条射线和3个slab的相交部分必定有重合部分。
- 性质三:当射线与这三个候选面中的一个发生交叉之后,射线Ray的原点到这个面的距离要比到其他几个面的距离要长。
性质一和性质二比较容易理解,如果射线和3个slab的相交线段没有重合,那么这些线段就不可能同时存在于3个slab中,也就不可能在AABB盒子中。
为了方便理解性质三,使用2D图形来讲解:

在上图中,我们的射线在右下角,向左上角发射,射线经过一个A点,其中候选面是y1面和x2面。
根据上述性质,可以看到A点同时在2D空间中的2个slab中;此外,根据性质二,因为射线与平面相交,那么这条射线与slab的相交部分必有重合部分,因为A点在射线上,且在平面中,那么可以得到max(t1,t2)<=tA<=min(t3,t4);根据性质三:当交叉后,可以看出t2>t1。
同理,我们可以把上述的验证过程推广到三维中。在三维空间中,假设射线到3个候选面的距离分别是t1、t2、t3,到候选面对应的面的距离分别为t4、t5、t6,那么根据性质二,射线与AABB碰撞的条件是max(t1,t2,t3)<=min(t4,t5,t6);如果发生交叉,那么根据性质三,射线到最近的交叉面的距离是是max(t1,t2,t3)。
在上述性质基础上,确定射线与AABB是否交叉需要三步骤:
- 如何确定候选面:只要将平面方程带入射线Ray的方程,求出这两个平面的t值,然后t值较小的那个自然先与射线交叉,那么就表示它是一个候选面。射线可以用参数方程表示为R(t) = P0 + t·d, (其中P0为射线起点,d为射线的方向向量)
- 如何确定候选面的方程。平面由隐式定义方程X·n=D, (其中X为平面上的点,n为平面法向量,D为原点到平面的距离)给出。由于AABB的slab平面都分别和两个坐标轴平行,它的面的法线总是有两个分量是0,而另外一个分量总是为1,所以我们一致使用某个轴分量为1的法线。如果上面的方程表示的是AABB盒的左面的面,那么公式中的n表示的就是(1,0,0),但上面的公式表示的是AABB盒的右边的面的时候,n表示的值依然是(1,0,0)。
- 如何对交叉点是否在AABB盒上进行判断。根据性质二判断,即射线与AABB碰撞的条件是max(t1,t2,t3)<=min(t4,t5,t6)。
碰撞检测算法公式推导
求取t值的公式推导如下:
碰撞检测算法Python源代码
最后,附上我的Python代码片段,代码实时更新于GitHub
# Ray-AABB方法 相交返回True,否则返回False
# TDPoint = collections.namedtuple("TDPoint", ["x", "y","z"])
# AABB有最大和最小点组成,数据结构为{max=TDPoint,min=TDPoint}
# Ray由原点和方向组成,其中方向矢量为1,数据结构为{TDPoint,TDPoint}
def intersectWithAABB(AABB,Ray):
tmin=0
tmax=10000
# <editor-fold desc="平行于x轴">
if(math.fabs(Ray[1].x)<0.000001):
if (Ray[0].x<AABB.min.x) or (Ray[0].x>AABB.max.x):
return False
else:
ood=1.0/Ray[1].x
t1=(AABB.min.x-Ray[0].x)*ood
t2=(AABB.max.x-Ray[0].x)*ood
# t1做候选平面,t2做远平面
if (t1>t2):
temp=t1
t1=t2
t2=temp
if t1>tmin:
tmin=t1
if t2<tmax:
tmax=t2
if tmin>tmax:
return False
# </editor-fold>
# <editor-fold desc="平行于y轴">
if(math.fabs(Ray[1].y)<0.000001):
if (Ray[0].y<AABB.min.y) or (Ray[0].y>AABB.max.y):
return False
else:
ood=1.0/Ray[1].y
t1=(AABB.min.y-Ray[0].y)*ood
t2=(AABB.max.y-Ray[0].y)*ood
# t1做候选平面,t2做远平面
if (t1>t2):
temp=t1
t1=t2
t2=temp
if t1>tmin:
tmin=t1
if t2<tmax:
tmax=t2
if tmin>tmax:
return False
# </editor-fold>
# <editor-fold desc="平行于z轴">
if(math.fabs(Ray[1].z)<0.000001):
if (Ray[0].z<AABB.min.z) or (Ray[0].z>AABB.max.z):
return False
else:
ood=1.0/Ray[1].z
t1=(AABB.min.z-Ray[0].z)*ood
t2=(AABB.max.z-Ray[0].z)*ood
# t1做候选平面,t2做远平面
if (t1>t2):
temp=t1
t1=t2
t2=temp
if t1>tmin:
tmin=t1
if t2<tmax:
tmax=t2
if tmin>tmax:
return False
# </editor-fold>
return True
from 3D空间中射线与轴向包围盒AABB的交叉检测算法
from Box2D 射线和AABB的碰撞检测
我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan
Ray-AABB交叉检测算法的更多相关文章
- 3D空间中射线与轴向包围盒AABB的交叉检测算法【转】
引言 在上一节中,我讲述了如何实现射线与三角形的交叉检测算法.但是,我们应该知道,在游戏开发中,一个模型有很多的三角形构成,如果要对所有的物体,所有的三角形进行这种检测,就算现在的计算机运算能力,也是 ...
- 3D空间中射线与轴向包围盒AABB的交叉检测算法 【转】
http://blog.csdn.net/i_dovelemon/article/details/38342739 引言 在上一节中,我讲述了如何实现射线与三角形的交叉检测算法. 但是,我们应该知道, ...
- 3D空间中射线与三角形的交叉检测算法【转】
引言 射线Ray,在3D图形学中有很多重要的应用.比如,pick操作就是使用射线Ray来实现的,还有诸如子弹射线的碰撞检测等等都可以使用射线Ray来完成.所以,在本次博客中,将会简单的像大家介绍下,如 ...
- 【深度学习】目标检测算法总结(R-CNN、Fast R-CNN、Faster R-CNN、FPN、YOLO、SSD、RetinaNet)
目标检测是很多计算机视觉任务的基础,不论我们需要实现图像与文字的交互还是需要识别精细类别,它都提供了可靠的信息.本文对目标检测进行了整体回顾,第一部分从RCNN开始介绍基于候选区域的目标检测器,包括F ...
- yolo类检测算法解析——yolo v3
每当听到有人问“如何入门计算机视觉”这个问题时,其实我内心是拒绝的,为什么呢?因为我们说的计算机视觉的发展史可谓很长了,它的分支很多,而且理论那是错综复杂交相辉映,就好像数学一样,如何学习数学?这问题 ...
- 如何开发一个异常检测系统:使用什么特征变量(features)来构建异常检测算法
如何构建与选择异常检测算法中的features 如果我的feature像图1所示的那样的正态分布图的话,我们可以很高兴地将它送入异常检测系统中去构建算法. 如果我的feature像图2那样不是正态分布 ...
- 检测算法简介及其原理——fast R-CNN,faster R-CNN,YOLO,SSD,YOLOv2,YOLOv3
1 引言 深度学习目前已经应用到了各个领域,应用场景大体分为三类:物体识别,目标检测,自然语言处理.本文着重与分析目标检测领域的深度学习方法,对其中的经典模型框架进行深入分析. 目标检测可以理解为是物 ...
- 目标检测算法的总结(R-CNN、Fast R-CNN、Faster R-CNN、YOLO、SSD、FNP、ALEXnet、RetianNet、VGG Net-16)
目标检测解决的是计算机视觉任务的基本问题:即What objects are where?图像中有什么目标,在哪里?这意味着,我们不仅要用算法判断图片中是不是要检测的目标, 还要在图片中标记出它的位置 ...
- FCOS : 找到诀窍了,anchor-free的one-stage目标检测算法也可以很准 | ICCV 2019
论文提出anchor-free和proposal-free的one-stage的目标检测算法FCOS,不再需要anchor相关的的超参数,在目前流行的逐像素(per-pixel)预测方法上进行目标检测 ...
随机推荐
- pageX,clientX,offsetX,screenX,offsetLeft,style.left,offsetWidth,scrollWidth的区别以及使用详解
https://www.cnblogs.com/echolun/p/9231760.html
- Typora中给代码块设置快捷键
Tpyore中大部分的操作都是有快捷键的.但是有那么几个常用的却没有快捷键.就比如代码块,这个常用的操作,还有有序无需列表. 下边教会你怎么设置快捷键,打开设置,Preferences[偏好设置],然 ...
- Linux下安装&运行Jmeter程序
Jmeter在linux系统中运行需要安装jdk和Jmeter两个软件: 1.安装JDK 先检查系统是否有安装jdk,在linux中执行如下命令:java -version 如果返回版本信息,说明系 ...
- Kure讲HTML_div标签和table标签
为什么要把这两个标签放在一起讲? 个人认为div标签可以算是一个万能标签,它可以通过CSS(层叠样式表)来模仿表格的形式来生成一个表格.那么很多人可能会疑惑那在开发的时候,到底是用div+css的形式 ...
- java 数字进制之间转换
//10进制转换 16进制 System.out.println(Integer.toHexString(val)); System.out.println(String.format("% ...
- 在cms以及kindeditor中插入百度动态地图的方法
想在网页中插入动态地图不难,直接打开网址http://api.map.baidu.com/lbsapi/creatmap/,然后按照提示操作,最终生成脚本,放到html文件中即可.而在kindedit ...
- 会话状态在此上下文中不可用HttpModule中无法访问Session原因
写了一个自定义HttpModule,但始终访问不了Session,代码如下: public class RouteModule : IHttpModule, System.Web.SessionSta ...
- springboot2.x如何添加事务
什么时候需要添加事务呢?一般情况下,如果该方法有两条SQL语句或者以上都需要添加(个人感觉:)). 首先需要在我们的启动类加上 @EnableTransactionManagement //开启事务管 ...
- position的参考基准
static(静态):position默认的样式:占据标准流的位置, 它会忽略top.bottom.left . right 的设置 relative(相对): 占据标准流的位置:可将其移至相对于其正 ...
- 创建Podspec 并且发布到github spec
昨天,花了点时间,把自己的代码做成framework,但是发现,每次迁移项目或者更新项目都是一件很头疼的事情,索性,也跟着时尚了一回,把所有代码都扔到git里面进行管理,通过cococapods直接安 ...