您的位置:首页 > 其它

DirectX 11 射线和3D物体的碰撞检测(Ray AABB)

2018-01-12 07:18 363 查看
数学部分

A.1 平面的直线方程(法线式):x·cosα+y·sinα-d=0(α为直线倾斜角,d为原点到该直线的最短距离)



A.2 空间的平面方程(法线式):x·cosα+y·cosβ+z·cosγ-d=0(α、β、γ为平面绕三个轴的旋转角(欧拉),d为原点到该平面的最短距离)

▲实际A.2是A.1二维到三维的递推公式。

▲A.1只有α没有β是因为其中的y·sinα就等于y·cosβ

令射线从点O发射,方向向量为f,则有

B.1射线公式:r = f·t+O (参照初中直线方程y=kx+b)

借助公式A.2,则有

B.2参与碰撞检测的平面公式:P·n = d

▲B.2相对难懂,补充一下:

参考前面的A.2,P为平面上任意点(在这里为射线和平面之交),n为平面的法向量的方向余弦,d为原点到该平面的距离。

所以设P为(x,y,z),设n的方向余弦为(α,β,γ),则P·n实际就等于x·cosα+y·cosβ+z·cosγ,没毛病。

因为射线和平面相交,且交点为P,则结合B.1,B.2得

B.3 (f·t+O)·n = d

可推导出

B.4 t = (d - O·n)/(f·n)

△肯定要先推导出t,这样才能求出在射线的什么位置和平面相交。

矩阵变换

我的使用场景是通过点击鼠标发送射线,因为本文只讲解碰撞算法的检测,故对如何把鼠标坐标转化成直线的问题,不做赘述。

通过鼠标获取的射线目前处于 view 矩阵,而我们要计算碰撞检测的物体处于 local 矩阵。肯定要把两个物体的坐标参照矩阵转化成相同的,才能进行碰撞检测计算,只是转化谁比较合适的问题。DX11 龙书 16.2 章给出的建议是将射线的 view 矩阵转化成 local,而碰撞物体的 local 不变。

Local 坐标转化为 View 坐标可通过 C(View)= C(Local)* M(World)* M(View) 的方法转换,而我们需要的是从 View 坐标逆推回 Local 坐标,则得到公式 C(Local)= C(View)* invM(View)* invM(World),其中 invM 表示 M 的逆矩阵。更细节处和本问题无关,可参考龙书,在此省略。

在将射线从 View 转化为碰撞物体的 Local 坐标后,才可以开始进行碰撞检测。

基于slab的碰撞检测

本文采用基于 slab 的算法进行碰撞检测。slab 算法不是我的原创,只给出关键图,原理讲解部分省略。



从二维扩展到三维,检测碰撞只需要判断物体的 x-slab,y-slab,z-slab 之间是否有公共区域。

而在本文中,表现射线的区间位置的关键变量,是 B.4 中的 t。

令 O =(Ox,Oy,Oz),射线方向 f =(fx,fy,fz)

C.1 则取 x 坐标,x-slab 的计算方法为 t =(d - O·Ox)/ f·fx。y,z 方向同理。(使用公式 B.4)

之前在 A.2 中说过,d 是原点到平面的距离。在这里表示原点到 AABB 包围盒的距离。而 AABB 包围盒是一个和三轴对齐的立方体,因此只需得到 AABB 的 min 坐标和 max 坐标,就可以得知 +x,-x,+y,-y,+z,-z 六个方向的 d 值。

可在 x-slab 中算出 t 在 +x,-x 方向的 d 值。y,z 方向同理。(使用 C.1)

在得到六个方向的 d 值后,剩下的就是判断区间 [dx+,dx-],[dy+,dy-],[dz+,dz-] 是否存在公共区域。如果 dx-,dy-,dz- 中的最大值 < dx+,dy+,dz+ 的最小值,则三段区间必有公共区域。则射线和物体的AABB必相交。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: