简介
射线检测可以用于拾取物体、判断前方是否有障碍物、判断是否碰撞等场景,本文介绍射线与圆的检测原理。
原理
射线与圆的检测,有以下几点判断:
射线方向是否与射线起点与圆的方向相反,是则不相交;
射线是否过短,是则不相交;
如图所示,射线 R 在射线原点与圆心方向的投影加上圆 C 的半径长度之和小于射线原点与圆心的距离 RC,射线过短。(黑线表示距离和,蓝线表示 RC)
射线是否在园内,是则必定相交;
当射线与圆相交的时候,如下图所示:
我们投影射线原点与圆心的距离 d 到射线 R 上,记为 p,并通过圆心作一条垂直于射线 R 的垂线 g,我们可以得到如下关系: f1
: $p^2+g^2=d^2$
我们把交点到射线原点的距离记为 t,到垂线 g 的距离记为 s,线段 s 满足以下关系:f2
: $s^2+g^2=r^2$
我们合并两个三角形方程f1
、f2
,得到方程 $p^2+g^2-s^2+g^2=d^2-r^2$,化简得到:f3
: $s^2=p^2-d^2+r^2$
由此可知,如果射线与圆相交,则以上等式恒成立,即如果以上等式不成立的情况下,射线与圆不相交。因此我们判断方程f3
的情况是否成立,开根号得到: f4
: $s=\pm\sqrt[]{p^2-d^2+r^2}$,那么我们只要判断$p^2-d^2+r^2>=0$就知道射线与圆是否相交,p、d、r 均为已知数。
当我们要求交点的时候,我们只要带入上文已求的 p 和 s,得到近点距离为:$t=p-s$;远点距离为:$t=p+s$,然后以射线原点出发,加上方向向量的单位向量乘以距离,即可求出交点。
对于三维空间来说,我们求的也是射线与球的一个面,即圆的关系。因此算法和二维空间一样。
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
| public class CollisionData : MonoBehaviour { public Vector3 center = Vector3.zero; public float radius = 1.0f; public Vector3 direction = Vector3.zero; } ---------------------------------------------
private bool CollisionRay2Circle(CollisionData data1,CollisionData data2) {
Vector3 centerDis = data2.center - data1.center; Vector3 direction = data1.direction;
float projection = Vector3.Dot(centerDis, direction); float r2 = Mathf.Pow(data2.radius, 2); float f = Mathf.Pow(projection, 2) + r2 - centerDis.sqrMagnitude;
bool checkDirection = projection < 0; bool checkDistance = centerDis.sqrMagnitude > Mathf.Pow(data1.radius + data2.radius, 2); bool checkNotInside = centerDis.sqrMagnitude > r2; bool checkNotCollide = f < 0;
if (checkNotInside && (checkDirection || checkDistance || checkNotCollide)) { return false; }
float dis = projection - Mathf.Sqrt(f) * (checkNotInside ? 1 : -1); Vector3 point = data1.center + data1.direction * dis; ConsoleUtils.Log("碰撞点", point);
return true; }
|
碰撞检测示例工程