射线与平面相交检测
作者:互联网
射线与平面相交检测
3D 中射线与平面相交检测
本篇讨论的射线是无限长,平面无限大
下图展示的几种位置关系:相交、不相交
相交包括:只有一个交点 (射线3)、射线在平面内有无数交点 (射线4)
不相交:射线与平面平行 (射线1),射线与平面不平行也不相交 (射线2、射线5)
判断射线2和射线5和平面不相交,添加辅助线如下
在平面上任取一点C
射线2中:P1为射线起点,向量P1A 是射线的方向向量, 连接P1C
点乘:Dot(向量P1A,平面法向量 Normal) > 0
点乘:Dot(向量P1C,平面法向量 Normal < 0
两个点乘结果异号(一个大于0,一个小于0) 则判定射线2 与平面不相交
射线5中:P2为射线起点,向量 P2B 是射线的方向向量,连接P2C
点乘:Dot(向量P2B,平面法向量 Normal) < 0
点乘:Dot(向量P2C,平面法向量 Normal > 0
两个点乘结果异号(一个大于0,一个小于0) 则判定射线2 与平面不相交
判断射线1、射线4,添加辅助线如下图
在平面上任取一点C
射线1中:P1为射线起点,向量P1A 是射线的方向向量, 连接P1C
点乘:Dot(向量P1A,平面法向量 Normal) = 0 说明 P1A 垂直于平面法向量,则P1A平行于平面
点乘:Dot(向量P1C,平面法向量 Normal < 0 说明 P1C 至少一个端点不在平面上
两个点乘结果(一个等于0,一个小于0) 则判定射线2 与平面平行但不在平面内
射线4中:P2为射线起点,向量 P2B 是射线的方向向量,连接P2C
点乘:Dot(向量P2B,平面法向量 Normal) = 0 说明 P2B 垂直于平面法向量,则P2B平行于平面
点乘:Dot(向量P2C,平面法向量 Normal = 0 说明 P2C 垂直于平面法向量,则P2C平行于平面
则 P2BC 所组成的平面和原平面平行,C点又是原平面中的点,则P2BC和平面重合,则P2B在原平面内
结论射线4在平面内
射线3的相交检测,如果相交,求交点坐标。看下图辅助线以及标记
平面上任取一点C
PB 为从点P到平面做的垂线,h 为向量PB 的长度
O为射线3与平面的交点,f 为向量PO的长度,
O点坐标 = P坐标 + 向量PO
向量PO = 射线3方向向量(rayDirection 单位向量) * f 简写为 rayDirection * f
O点坐标 = P坐标 + rayDirection * f
我们通过点C来求解 f
在三角形 PBC 中
h = Math.Abs( Dot(向量PC,平面法向量Normal)) 因为我需要的是长度,所以取绝对值
这一步可以得到 h 的值。
在三角形 PBO 中
h = Math.Abs( Dot(向量PO,平面法向量Normal)) 然后将 向量PO = rayDirection * f 带入公式
h = Maht.Abs(Dot(rayDirection * f,平面法向量Normal), 平面法向量 Normal),其中 f 是标量,可以提取出来
h = f * Maht.Abs(Dot(rayDirection * f, 平面法向量 Normal)
f = h 除以 Maht.Abs(Dot(rayDirection, 平面法向量 Normal)
最终O坐标 = P坐标 + rayDirection * f
代码逻辑如下
/// <summary>
/// 射线与平面相交检测
/// </summary>
public class RayPlaneCollision
{
float dot_rayDir_planeNormal;
float dot_pa_planeNormal;
/// <summary>
/// 射线与平面相交检测
/// </summary>
/// <param name="source">射线起点坐标</param>
/// <param name="rayDirection">射线方向</param>
/// <param name="planePos">平面上任一点坐标</param>
/// <param name="planeNormal">平面法向量</param>
/// <returns></returns>
public RayPlaneCollisionEnum IsCollision(Vector3 source, Vector3 rayDirection, Vector3 planePos, Vector3 planeNormal)
{
Vector3 PC = planePos - source;
dot_rayDir_planeNormal = Dot(rayDirection, planeNormal);
dot_pa_planeNormal = Dot(PC, planeNormal);
// 射线平行于平面
if (dot_rayDir_planeNormal == 0)
{
if (dot_pa_planeNormal == 0)
{
// 射线和平面平行并且射线在平面内
return RayPlaneCollisionEnum.IN_PLANE;
}
// 射线和平面平行但是射线不在平面内
return RayPlaneCollisionEnum.SEPARATION;
}
if (dot_rayDir_planeNormal > 0 && dot_pa_planeNormal > 0)
{
return RayPlaneCollisionEnum.COLLISION;
}
if (dot_rayDir_planeNormal < 0 && dot_pa_planeNormal < 0)
{
return RayPlaneCollisionEnum.COLLISION;
}
return RayPlaneCollisionEnum.SEPARATION;
}
public Vector3 CollisionPosition(Vector3 source, Vector3 rayDirection, Vector3 planePos, Vector3 planeNormal)
{
if (IsCollision(source, rayDirection, planePos, planeNormal) != RayPlaneCollisionEnum.COLLISION)
{
return Vector3.zero;
}
float length = dot_pa_planeNormal / dot_rayDir_planeNormal;
Debug.LogError(dot_pa_planeNormal + " " + dot_rayDir_planeNormal);
return source + rayDirection * length;
}
public float Dot(Vector3 vector1, Vector3 vector2)
{
return vector1.x * vector2.x + vector1.y * vector2.y + vector1.z * vector2.z;
}
}
本篇开始说的限制条件 射线无限长、平面无限大,如果射线限制了长度 s,平面限制了区域(有N个顶点的多边形),对于不相交的判定没有影响
对于射线和平面相交的,如果射线限制长度,则 根据上边计算的长度 f 和 限制长度 s 比较,如果 s 小于 f,则射线长度不够,不相交
如果 s >= f,计算出 O 点坐标,然后判断 O点坐标是否在平面范围内
对于射线在平面内的思考下
标签:Normal,相交,planeNormal,射线,向量,平面,Dot 来源: https://blog.csdn.net/LIQIANGEASTSUN/article/details/119462082