检测光线是不是与对象相交的函数

Posted

技术标签:

【中文标题】检测光线是不是与对象相交的函数【英文标题】:function that detects if a ray is intersecting an object检测光线是否与对象相交的函数 【发布时间】:2018-01-13 19:17:39 【问题描述】:

我有一个函数可以检测光线是否与对象相交,但它使用对象中心周围的半径,我希望它与边界框一起使用,我想给它 2 Vector3D 的边界框,以及射线原点的一个向量和射线的方向之一,它会计算是否有交叉点,有人可以帮我吗?这个的数学公式是什么?

intersectRay(origin:Vector3D, dir:Vector3D):

【问题讨论】:

信息不足。 (1) 你说的是 2D 还是 3D? (2) 即使是更简单的 2D 情况,边界框也是一个矩形 (x,y,width,height),而射线由原点 (x,y) 和方向向量 (x,y) 表示。如果是3D,那么bounding box应该是(x,y,z,width,height,depth),ray分别是原点(x,y,z)和方向(x,y,z)。 您应该将该功能填充到您的边界框类中。 2D 边界框并不总是与轴对齐(例如,它可以转动),对于 3D,给定的 3D 框有 3 个可能的转动。如果你的盒子都是轴对齐的,那么你就有足够的数据来组成一个检查器。有一些 C++ 实现这样的检查,找到一个,适应和使用。没有确切的公式,但在 XY、XZ 和 YZ 中进行 3 次检查并进行比较。 我说的是3d,我想创建一个边界框作为对象的简化,在3DMax中,边界框将有8个向量但它们不一定是a的形状框,我想找到一个简单的公式来从相机发送一条带有原点和方向的光线,该公式将检查光线是在边界框内还是在边界框外交叉 真相是我需要它在 2D 中,我想使用角度计算命中,我会找到边界框的最左边和最右边的点并计算从原点开始的角度的射线到两个点,然后我会知道在 x 轴上击中目标的角度范围,然后我会在 y 轴上做同样的事情,我不能使用我不使用的太复杂的数学'不明白,我现场没有太多物体,我只检查日落事件。我所需要的只是一个函数,它将给出 x 轴上 2 个点和 y 轴上另一个度数之间的度数。 这样我将 3D 问题投影到 2D 平面上,我现在需要做的就是找到外部点,用线将它们连接成一个封闭的形状,然后看看鼠标是否被选中形状内部或外部的一个点。 【参考方案1】:

找到了解决办法。 1. 我使用 8 个点的边界框,每个点对应每个角。 2. 我用这个函数给每个点在 2D 平面上的 x 和 y 位置,这样我把 3D 问题变成了 2D 问题,x 和 y 实际上是点相对于相机位置的水平角和相对于相机位置点的垂直角度:

    public function AngleBetween2vectors(v1:Vector3D,v2:Vector3D):Point
    
        var angleX:Number = Math.atan2(v1.x-v2.x,v1.z-v2.z);
        angleX = angleX*180/Math.PI;

        var angleY:Number = Math.atan2(v1.y-v2.y,v1.z-v2.z);
        angleY = angleY*180/Math.PI;

        return new Point(angleX,angleY);

    

    然后我使用凸包算法删除不属于外部轮廓多边形的点,该点在屏幕上标记对象的位置,可以在网上找到,确保边界框没有'不包含重复的点,比如如果你有一个没有深度的平坦平原,这可能会给算法带来问题,所以当你创建边界框时将它们清除掉。

    然后我使用这个算法来确定鼠标点击的点是在这个多边形内还是在它之外:

        private function pnpoly( A:Array,p:Point ):Boolean
    
        var i:int;
        var j:int;
        var c:Boolean = false;
        for( i = 0, j = A.length-1; i < A.length; j = i++ ) 
            if( ( ( A[i].y > p.y ) != ( A[j].y > p.y ) ) &&
                ( p.x < ( A[j].x - A[i].x ) * ( p.y - A[i].y ) / ( A[j].y - A[i].y ) + A[i].x ) )
            
                c = !c;
            
        
        return c;
    
    

    然后我测量到物体的距离并选择离相机位置最近的一个,使用这个函数:

        public function DistanceBetween2Vectors(v1:Vector3D,v2:Vector3D):Number
    
        var a:Number = Math.sqrt(Math.pow((v1.x-v2.x),2)+Math.pow((v1.y-v2.y),2));
        var b:Number = Math.sqrt(Math.pow((v1.z-v2.z),2)+Math.pow((v1.y-v2.y),2));
        return Math.sqrt(Math.pow(a,2)+Math.pow(b,2));
    
    

我确信有更有效的方法,但这种方法很有趣,对我来说已经足够了,我喜欢它,因为它很直观,我不喜欢使用抽象数学,这很难对我来说,如果有错误,很难找到它。如果有人对我如何提高效率有任何建议,我会很高兴听到他们的意见。

【讨论】:

好答案。惊讶于人们仍在使用 Flash 进行游戏 Adobe Air 是一个跨平台的 SDK,为什么不用呢?你有更好的吗?我使用 Air 创建了应用程序,然后可以将其发布到任何平台 - PC、MAC、android、iPhone,你知道还有什么东西可以给你吗? 您的标签上写的是“flash”而不是 Adob​​e Air。 Flash 不会在移动设备上作为本机运行。您在问题中标记了 flash 和 actionscript,它们都是dying,很快就会消失。我认为他们的支持很快就会停止。还有其他选项,例如用于应用程序的 Xamarin 和用于游戏的 Unity。再说一次,我不是告诉你你用什么,我只是提醒你,你正在使用的东西很快就会停产。 好吧,我说的不是 Flash 播放器,我是指 Flash 动画程序,现在称为 Animate cc。或 Flash 生成器。无论如何,我可以做一个应用程序,然后将其导出到所有平台、智能手机和桌面,你不会告诉我要使用什么,但我很想知道是否有其他工具可以为你提供相同的功能。 “Xamarin 应用程序和 Unity 游戏”是否适合在所有平台上发布?它们真的是跨平台的还是只是使用本地浏览器对象?

以上是关于检测光线是不是与对象相交的函数的主要内容,如果未能解决你的问题,请参考以下文章

5 光线/二次曲面 相交和映射

光线追踪框相交

Three.js raycaster 可以与组相交吗?

OpenGL 射线 OBB 相交

OpenGL拾取 - 光线/球体相交错误

C中的光线追踪器,光线平面相交