射线与平面相交检测

射线与平面相交检测

3D 中射线与平面相交检测
本篇讨论的射线是无限长,平面无限大
下图展示的几种位置关系:相交、不相交
相交包括:只有一个交点 (射线3)、射线在平面内有无数交点 (射线4)
不相交:射线与平面平行 (射线1),射线与平面不平行也不相交 (射线2、射线5)

射线与平面相交检测_第1张图片

判断射线2和射线5和平面不相交,添加辅助线如下
射线与平面相交检测_第2张图片
在平面上任取一点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,添加辅助线如下图
射线与平面相交检测_第3张图片

在平面上任取一点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的相交检测,如果相交,求交点坐标。看下图辅助线以及标记
射线与平面相交检测_第4张图片
平面上任取一点C
PB 为从点P到平面做的垂线,h 为向量PB 在平面法向量 Normal 的投影长度
O为射线3与平面的交点,f 为向量PO的长度,
O点坐标 = P坐标 + 向量PO
向量PO = rayDirection * f
O点坐标 = P坐标 + rayDirection * f
我们通过点C来求解 f

在三角形 PBC 中
h = Dot(向量PC,平面法向量Normal)

在三角形 PBO 中
h = Dot(向量PO,平面法向量Normal)

h = Dot(rayDirection * f,平面法向量Normal), 其中 f 是标量,可以提取出来

h = f * Dot(rayDirection , 平面法向量 Normal)

f = h 除以 Dot(rayDirection, 平面法向量 Normal)

代码逻辑如下

/// 
/// 射线与平面相交检测
/// 
public class RayPlaneCollision
{

    float dot_rayDir_planeNormal;
    float dot_pc_planeNormal;

    /// 
    /// 射线与平面相交检测
    /// 
    /// 射线起点坐标
    /// 射线方向
    /// 平面上任一点坐标
    /// 平面法向量
    /// 
    public RayPlaneCollisionEnum IsCollision(Vector3 source, Vector3 rayDirection, Vector3 planePos, Vector3 planeNormal)
    {
        Vector3 PC = planePos - source;
        dot_rayDir_planeNormal = Dot(rayDirection, planeNormal);
        dot_pc_planeNormal = Dot(PC, planeNormal);

        // 射线平行于平面
        if (dot_rayDir_planeNormal == 0) 
        {
            if (dot_pc_planeNormal == 0)
            {
                // 射线和平面平行并且射线在平面内
                return RayPlaneCollisionEnum.IN_PLANE;
            }
            // 射线和平面平行但是射线不在平面内
            return RayPlaneCollisionEnum.SEPARATION;
        }

        if (dot_rayDir_planeNormal > 0 && dot_pc_planeNormal > 0)
        {
            return RayPlaneCollisionEnum.COLLISION;
        }

        if (dot_rayDir_planeNormal < 0 && dot_pc_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_pc_planeNormal / dot_rayDir_planeNormal;

        Debug.LogError(dot_pc_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点坐标是否在平面范围内

对于射线在平面内的思考下

你可能感兴趣的:(3D数学基础图形,射线与平面相交检测)