LineSegmentIntersector::Intersections中ratio含义及LineSegmentIntersector相交点说明

文章讲述了如何利用osg和osgUtil库中的LineSegmentIntersector和IntersectionVisitor类计算线段与三维模型的交点,通过示例代码展示了计算过程。在特定情况下,由于OpenGL将四边形拆分为两个三角形绘制,导致交点重复计算。此外,当长方体尺寸小于1时,可能出现交点输出异常。作者提出了遇到的问题并希望得到解答。
摘要由CSDN通过智能技术生成

osg用osgUtil库中的LineSegmentIntersector、IntersectionVisitor类来求线段和三维模型的交点。如下代码:

#include <osgViewer/Viewer>
#include <osgUtil/IntersectionVisitor>
#include <osgUtil/LineSegmentIntersector>
#include<iostream>

//创建盒子
osg::ref_ptr<osg::Geode> createBox()
{
    osg::ref_ptr<osg::Geode> geode1 = new osg::Geode;
    auto box1 = new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0, 0.0, 0.0), 10.0, 8.0, 6.0));
    geode1->addDrawable(box1);

   // geode1->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0, 0.0, 0.0), 0.1, 0.1, 20)));
    return geode1;
}

int main(int argc, char *argv[])
{

    osg::ref_ptr<osgViewer::Viewer> viewer1 = new osgViewer::Viewer;
    osg::ref_ptr<osg::Group> group1 = new osg::Group;

    osg::ref_ptr<osgUtil::LineSegmentIntersector> lineSegmentIntesector = new osgUtil::LineSegmentIntersector(osg::Vec3(0, 0,15), osg::Vec3(0, 0, -15));
    osg::ref_ptr<osgUtil::IntersectionVisitor> intersectionVisitor1 = new osgUtil::IntersectionVisitor(lineSegmentIntesector);

    group1->addChild(createBox());
    group1->accept(*intersectionVisitor1.get());

    osgUtil::LineSegmentIntersector::Intersections intersections;

    //输出交点
    intersections = lineSegmentIntesector->getIntersections();
    osgUtil::LineSegmentIntersector::Intersections::iterator iter;
    for (iter = intersections.begin(); iter != intersections.end(); ++iter)
    {
        std::cout << "ratio:" << "   " << iter->ratio << "    x:" << iter->getWorldIntersectPoint().x() << "    y:" << iter->getWorldIntersectPoint().y() << "    z:" << iter->getWorldIntersectPoint().z() << std::endl;
    }

    viewer1->setSceneData(group1.get());
    viewer1->setUpViewInWindow(200, 200, 800, 600, 0);

    return viewer1->run();
}

上述代码构建了一条线段,线段起始坐标如下:

Vec3(0, 0,15)

 终点坐标如下:

osg::Vec3(0, 0, -15)

同时构建了一个长方体,长方体中心位于原点,长、宽、高、分别为:5、4、3。

效果如下(注意:为了便于观察,我使这个长方体绕X轴逆时针转动了一定角度):

                                                                图1

 上述代码的第23、24行构造了一个求交器和求交访问器对象。通过求交器和求交访问器对象相互协同合作,再通过调用第27行代码accept函数,就能求出线段和长方体的交点,结果如下:

图2 

  其中ratio含义如下:                     

        线段起点到交点之间的长度 / 线段总长度

           即:线段起点和交点之间的长度占线段总长度的比例。上例子,线段起点z坐标为15,线段在Z轴的总长度为15 -(-15) = 30,由图2知道,第1个交点的长方体z坐标为3,则第1个ratio为: 

                   ( 15 - 3 ) / 30 = 0.4

       同样地,可以算出最后一个交点的ratio为:                    

                   [ 15 - (-3 )] / 30 = 0.6

当把第27行线段的起始点、终止点坐标换成如下代码:

osg::ref_ptr<osgUtil::LineSegmentIntersector> lineSegmentIntesector = new osgUtil::LineSegmentIntersector(osg::Vec3(1, 5, 2), osg::Vec3(15, 0, -2));

则结果如下:

图3 

 则根据上面提到的计算ratio方法,线段起点z坐标为2,线段在Z轴的总长度为2 -(-2) = 4,由图3知道,第1个交点的长方体z坐标为1.2,则第1个ratio为: 

                       (2 - 1.2) / 4.0 =  0.2

同理,第2个ratio为:

                           ( 2 - 0.857143 ) / 4 = 0.285714

在平时的开发中,可以根据ratio知道交点占据整个线段z轴的比例。

      在图2中,可以看到第1、2个交点是同一个点;第3、4个交点也是同一个点,为何出现两个相同的交点?下面分析如下:

       通过断点跟进到底层源码发现:虽然长方体6个面是四边形,但OPenGl是通过绘制两个三角形来实现一个四边形的。即长方体上顶面、下底面的四边形绘制如下:

 图4

通过在for循环中循环2次绘制两个三角形从而形成四边形(四边形由两个三角形拼接而成,在底层硬件实现上,大部分多边形的绘制是分割为三角形进行绘制的,这样效率要高些)。第1次循环绘制v0v1v2(或v0v2v3)三角形,此时检测到线段和该三角形交于A点;第2次循环绘制v0v2v3(或v0v1v2)三角形,此时又检测到线段和该三角形交于A点,这就是上面交点被输出两次的原因。

       如果把上面代码的第13行改为如下:


    auto box1 = new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0, 0.0, 0.0), 0.1, 0.1, 20))

即把长方体宽、高尽量小,则结果如下(注意:为了便于观察,我使这个长方体绕X轴逆时针转动了一定角度):

 图5

可以看到,长方体上顶面和直线的交点只有一个,下底面和直线的交点符合前文提到的三角形描述,输出2个相同的交点值,长方体上顶面和下底面都平行于水平面,应该说上顶面和下底面没啥区别,都应该输出2个相同的交点值才行,跟踪到LineSegmentIntersector.cpp文件的intersect函数:

void intersect(const osg::Vec3& v0, const osg::Vec3& v1, const osg::Vec3& v2)
    {


          ....... // 其它代码略
              if ((u + v) > det)
            {
                return;       // 上顶面本来应该输出2个相同交点,但有一个三角形检测,从这里返回了
            }

           ....... // 其它代码略
   }

上顶面本来应该输出2个相同交点,但上顶面有一个三角形检测时,从return返回了,导致交点没插入交点容器,里面的算法不是很懂,希望懂的人留言交流,感谢了!。

           通过测试发现,只要长方体长、宽、高小于1时,都会存在这个问题。

更多关于这个类的知识,请参考如下博文:

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值