射线与AABB型包围盒相交算法

基础知识:

AABB包围盒,也叫轴对称包围盒,意思就是它的六个面总是分别平行XYZ三个轴的

相交计算原理:

计算射线与包围盒每个面的平面的交点,计算这个点是否在包围盒面的范围,在就是相交,不在就是没有相交

图解:

用个2D图形简单讲解一下
在这里插入图片描述

首先从图中可以看到射线Ray和红色的包围盒相交了,但是怎么计算出来(毕竟在3D世界中,不可能全靠眼睛去看…)

这个包围盒有4个面,2个平行于Y轴,2个平行于X轴,有两个关键点,最小点min和最大点max(即xy值最小和最大,有正负)

下面是伪代码

//首先是看射线Ray,这条射线的原点是origin,方向是direction,
Ray ray;
if(ray.origin.x < min.x)//原点的X小于min的X,那么测试射线与垂直于X轴的面的相交点。
{
    //假设射线的X方向到达min平面的时间为t
   float t   =   (min.x - _origin.x) / _direction.x;
    //那么可以计算出射线与平面的交点为hitPoint1
    Point hitPoint1 = ray.origin + ray.direction * t;
    if(hitPoint1.y> min.y && hitPoint.y < max.y)//比较,是不是在包围盒的面内
    {
        return true;
    }
}
if(ray.origin.y < min.y)//原点的y小于min的y,那么测试射线与垂直于Y轴的面的相交点。
{
   //假设射线的Y方向到达min平面的时间为t
   float t   =   (min.y - _origin.y) / _direction.y;
   //那么可以计算出射线与平面的交点为hitPoint2
   Point hitPoint1 = ray.origin + ray.direction * t;
    if(hitPoint1.x> min.x && hitPoint.x < max.x)//比较,是不是在包围盒的面内
    {
        return true;
    }
}

三维空间里也是同样的道理。

下面是OpenGLES三维空间射线与AABB盒相交的计算源码

 /**
        *   测试射线box相交
        *   如果相交,返回值中的first == true.否则false
        *   second为射线到点的距离
        *   调用getPoint方法,则返回交点
        */
	    std::pair<bool, T> intersects(const AxisAlignedBox<T>& box) const
        {
            T           lowt    = 0.0f;
            T           t;
            bool        hit     = false;
            tvec3<T>    hitpoint;
            tvec3<T>    min      =   box.getMinimum();
            tvec3<T>    max      =   box.getMaximum();

            /**
            *   点在包围盒里面
            */
            if ( _origin > min && _origin < max )
            {
                return std::pair<bool, T>(true, 0);
            }

            // Check each face in turn, only check closest 3
            // Min x
            if (_origin.x <= min.x && _direction.x > 0)
            {
                t   =   (min.x - _origin.x) / _direction.x;
                if (t >= 0)
                {
                    // Substitute t back into ray and check bounds and dist
                    hitpoint = _origin + _direction * t;
                    if (hitpoint.y >= min.y && 
                        hitpoint.y <= max.y &&
                        hitpoint.z >= min.z && 
                        hitpoint.z <= max.z &&
                        (!hit || t < lowt))
                    {
                        hit     =   true;
                        lowt    =   t;
                    }
                }
            }
            // Max x
            if (_origin.x >= max.x && _direction.x < 0)
            {
                t   =   (max.x - _origin.x) / _direction.x;
                if (t >= 0)
                {
                    // Substitute t back into ray and check bounds and dist
                    hitpoint = _origin + _direction * t;
                    if (hitpoint.y >= min.y && 
                        hitpoint.y <= max.y &&
                        hitpoint.z >= min.z &&
                        hitpoint.z <= max.z &&
                        (!hit || t < lowt))
                    {
                        hit     =   true;
                        lowt    =   t;
                    }
                }
            }
            // Min y
            if (_origin.y <= min.y && _direction.y > 0)
            {
                t   =   (min.y - _origin.y) / _direction.y;
                if (t >= 0)
                {
                    // Substitute t back into ray and check bounds and dist
                    hitpoint = _origin + _direction * t;
                    if (hitpoint.x >= min.x && 
                        hitpoint.x <= max.x &&
                        hitpoint.z >= min.z && 
                        hitpoint.z <= max.z &&
                        (!hit || t < lowt))
                    {
                        hit     =   true;
                        lowt    =   t;
                    }
                }
            }
            // Max y
            if (_origin.y >= max.y && _direction.y < 0)
            {
                t   =   (max.y - _origin.y) / _direction.y;
                if (t >= 0)
                {
                    // Substitute t back into ray and check bounds and dist
                    hitpoint = _origin + _direction * t;
                    if (hitpoint.x >= min.x &&
                        hitpoint.x <= max.x &&
                        hitpoint.z >= min.z &&
                        hitpoint.z <= max.z &&
                        (!hit || t < lowt))
                    {
                        hit     =   true;
                        lowt    =   t;
                    }
                }
            }
            // Min z
            if (_origin.z <= min.z && _direction.z > 0)
            {
                t   =   (min.z - _origin.z) / _direction.z;
                if (t >= 0)
                {
                    // Substitute t back into ray and check bounds and dist
                    hitpoint = _origin + _direction * t;
                    if (hitpoint.x >= min.x && 
                        hitpoint.x <= max.x &&
                        hitpoint.y >= min.y &&
                        hitpoint.y <= max.y &&
                        (!hit || t < lowt))
                    {
                        hit     =   true;
                        lowt    =   t;
                    }
                }
            }
            // Max z
            if (_origin.z >= max.z && _direction.z < 0)
            {
                t   =   (max.z - _origin.z) / _direction.z;
                if (t >= 0)
                {
                    // Substitute t back into ray and check bounds and dist
                    hitpoint = _origin + _direction * t;
                    if (hitpoint.x >= min.x && 
                        hitpoint.x <= max.x &&
                        hitpoint.y >= min.y && 
                        hitpoint.y <= max.y &&
                        (!hit || t < lowt))
                    {
                        hit     =   true;
                        lowt    =   t;
                    }
                }
            }
            return std::pair<bool, T>(hit, lowt);
        }
    };
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值