抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

简介

圆与 OBB 进行碰撞检测,和圆与 AABB 进行碰撞检测类似,实质可以化为一个点与 OBB 进行检测,然后根据检测结果与圆的半径进行比较。

原理

和圆与 AABB 碰撞检测类似,圆与 OBB 碰撞检测也是化为点与 OBB 检测。因此,我们需要把点的坐标化为 OBB 坐标系的坐标。这里我们利用投影,把点的坐标投影到 OBB 坐标系中,然后再使用点与 AABB 检测的思路进行检测,最后把得到的交点转换回原来的坐标系中。

如图所示,我们连接两个物体的中心点 C1 和 C2,得到一个距离向量 DIR(矩形中心到圆心)。然后我们把 dir 投影到矩形的坐标轴上,得到 X 方向的投影 X’和 Y 方向的投影 Y’,由此可以得出 C1 点在矩形坐标系中的位置。

然后我们利用圆与 AABB 检测的方法得到 OBB 上距离 C1 点的最近点,并且还原这个坐标到原始坐标轴中。具体方法是令最近点 Pnear 初始值为 C2 坐标,然后在求交点在每个轴坐标的时候让 P 的每个轴的值加上坐标值distance * 坐标轴向量的分量,即 Pnear.x += distance * axis[i].x ,以此类推。

得到最近点之后,我们就可以用和圆与 AABB 检测一样的方法来判断是否相交了。

三维空间和二维空间的求法一样,只不过多一个轴。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//包围盒数据结构
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CollisionData : MonoBehaviour
{
public Vector3 center = Vector3.zero;
public Vector3 extents = Vector3.zero;
public Vector3[] axes = new Vector3[3];
public float radius = 1.0f;
}
---------------------------------------------
/// <summary>
/// 球与OBB检测
/// <param name="data1"></param>
/// <param name="data2"></param>
/// </summary>
private bool CollisionCircle2OBB(CollisionData data1,CollisionData data2)
{
//求最近点
Vector3 nearP = GetClosestPointOBB(data1,data2);
//与AABB检测原理相同
float distance = (nearP - data1.center).sqrMagnitude;
float radius = Mathf.Pow(data1.radius, 2);
if (distance <= radius)
{
return true;
}
else
{
return false;
}
}

/// <summary>
/// 获取一点到OBB的最近点
/// <param name="data1"></param>
/// <param name="data2"></param>
/// </summary>
/// <returns></returns>
private Vector3 GetClosestPointOBB(CollisionData data1,CollisionData data2)
{
Vector3 nearP = data2.center;
//求球心与OBB中心的距离向量 从OBB中心指向球心
Vector3 center1 = data1.center;
Vector3 center2 = data2.center;
Vector3 dist = center1 - center2;

float[] extents = new float[3] { data2.extents.x, data2.extents.y, data2.extents.z };
Vector3[] axes = data2.axes;

for (int i = 0; i < 3; i++)
{
//计算距离向量到OBB坐标轴的投影长度 即距离向量在OBB坐标系中的对应坐标轴的长度
float distance = Vector3.Dot(dist, axes[i]);
distance = Mathf.Clamp(distance, -extents[i], extents[i]);
//还原到世界坐标
nearP.x += distance * axes[i].x;
nearP.y += distance * axes[i].y;
nearP.z += distance * axes[i].z;
}
return nearP;
}

其他

和圆与圆的检测一样,圆与 OBB 检测求两点距离的时候也使用平方来计算,减少开方的性能消耗。

碰撞检测示例工程

评论