• OSG碰撞检测


    http://bbs.vrchina.net/viewthread.php?tid=5196&extra=page%3D1
    OSG
    碰撞检测
    碰撞检测涉及到虚拟仿真的各个方面,这里我主要介绍两方面的应用:
    一 判断摄像机是否与前面的物体相撞
    基本原理如下图:
    首先确定摄像机的旧位置和新位置(此处的新位置是假设前方没有障碍物所行进到的新位置),然后利用两点创建一条线段,然后判断这条线段与模型是否有交点,如果存在交点,则取交点作为新位置(或者取交点稍前面的一点作为新位置)。

    1.jpg (16.32 KB)
    2008-1-27 07:07 PM

       











    二 摄像机按照地形来进行漫游:
    如果不进行碰撞检测的话,可能会出现一下两种情况:
    第一种情况,摄像机穿地形而过:

    2.JPG (11.76 KB)
    2008-1-27 07:12 PM








    第二种情况, 摄像机处于悬空状态

    3.JPG (9.14 KB)
    2008-1-27 07:12 PM










    对于第一种情况,摄像机肯定会与地形发生碰撞,但检测到碰撞之后,摄像机到达的位置
    是否位于地形法线上方的合适高度,需要进行另一次碰撞检测,如下图所示:

    4.JPG (9.3 KB)
    2008-1-27 07:12 PM






           


    绿色代表摄像机移动到的最终位置,从而保证了摄像机与地形之间的高度是固定的。
    对于第二种情况,可能在第一种情况的碰撞检测中检测不到碰撞,那么需要进行在一次碰撞检测,

    5.JPG (10.57 KB)
    2008-1-27 07:12 PM



           

           





    绿色代表摄像机移动到的最终位置,从而保证了摄像机与地形之间的高度是固定的。

    三 重要的类和函数

    osg::LineSegmen
    表示一个线段的类,包括一个起点和一个终点
    osgUtil::IntersectVisiotr
    接受线段的类,用于判别与节点的交集。
    其中的函数addLineSegment(line.get())用来添加一条线段到列表当中
    osgUtil::IntersectVisitor::HitList
    可以得到相交点的具体位置,从而计算出距离

    四 代码示例
    bool DriveManipulator::calcMovement()
    {
        //如果少于两个事件则返回错误
        if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false;
        double dt = _ga_t0->getTime()-_ga_t1->getTime();

        if (dt<0.0f)
        {
            notify(INFO) << "warning dt = "<<dt<< std::endl;
            dt = 0.0f;
        }
        switch(_speedMode)
        {
            case(USE_MOUSE_Y_FOR_SPEED):
            {//切换到鼠标上下控制速度模式
                double dy = _ga_t0->getYnormalized();
                _velocity = _modelScale*0.2f*dy;
                break;
            }
            case(USE_MOUSE_BUTTONS_FOR_SPEED):
            {//切换到鼠标按键控制速度模式
                unsigned int buttonMask = _ga_t1->getButtonMask();
                if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON)
                {   //左键加速
                    _velocity += dt*_modelScale*0.01;
                }
                else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON ||
                    buttonMask==(GUIEventAdapter::LEFT_MOUSE_BUTTON|GUIEventAdapter::RIGHT_MOUSE_BUTTON))
                {   //中键停止
                    _velocity = 0.0;
                }
                else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON)
                {   //右键减速
                    _velocity -= dt*_modelScale*0.01;
                }
                break;
            }
        }

        osg::CoordinateFrame cf=getCoordinateFrame(_eye);
        osg::Matrix rotation_matrix;
        rotation_matrix.makeRotate(_rotation);
        osg::Vec3d up = osg::Vec3d(0.0,1.0,0.0) * rotation_matrix;
        osg::Vec3d lv = osg::Vec3d(0.0,0.0,-1.0) * rotation_matrix;
        osg::Vec3d sv = osg::Vec3d(1.0,0.0,0.0) * rotation_matrix;

        //旋转摄像机
        double dx = _ga_t0->getXnormalized();
        double yaw = -inDegrees(dx*50.0f*dt);
       
    #ifdef KEYBOARD_PITCH
        double pitch_delta = 0.5;
        if (_pitchUpKeyPressed) _pitch += pitch_delta*dt;
        if (_pitchDownKeyPressed) _pitch -= pitch_delta*dt;
    #endif

    #if defined(ABOSULTE_PITCH)
        // abosolute pitch
        double dy = _ga_t0->getYnormalized();
        _pitch = -dy*0.5;
    #elif defined(INCREMENTAL_PITCH)
        // incremental pitch
        double dy = _ga_t0->getYnormalized();
        _pitch += dy*dt;
    #endif
       
        osg::Quat yaw_rotation;
        yaw_rotation.makeRotate(yaw,up);
        _rotation *= yaw_rotation;  
        rotation_matrix.makeRotate(_rotation);
        sv = osg::Vec3d(1.0,0.0,0.0) * rotation_matrix;

        if (fabs(_velocity*dt)>1e-8)
        {
            double distanceToMove = _velocity*dt;
            double signedBuffer;
            if (distanceToMove>=0.0) signedBuffer=_buffer;
            else signedBuffer=-_buffer;
            //检查前方是否有障碍物
            osgUtil::IntersectVisitor iv;
            iv.setTraversalMask(_intersectTraversalMask);
            osg::ref_ptr<osg::LineSegment> segForward = new osg::LineSegment;
            segForward->set(_eye,_eye+lv*(signedBuffer+distanceToMove));
            iv.addLineSegment(segForward.get());
            _node->accept(iv);
            //如果检测到碰撞
            if (iv.hits())
            {
                osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segForward.get());
                if (!hitList.empty())
                {
                    // notify(INFO) << "Hit obstruction"<< std::endl;
                    //取得碰撞交点
                    osg::Vec3d ip = hitList.front().getWorldIntersectPoint();
                    //计算移动距离
                    distanceToMove = (ip-_eye).length()-_buffer;
                    _velocity = 0.0;
                }
            }

            // 检查前进到的点是不是高于地形一个固定值
            osg::Vec3d fp = _eye+lv*distanceToMove;
            osg::Vec3d lfp = fp-up*_height*5;
            iv.reset();
            osg::ref_ptr<osg::LineSegment> segNormal = new osg::LineSegment;
            segNormal->set(fp,lfp);
            iv.addLineSegment(segNormal.get());
            _node->accept(iv);
            //第二次进行碰撞检测
            if (iv.hits())
            {
                osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segNormal.get());
                if (!hitList.empty())
                {
                    //notify(INFO) << "Hit terrain ok"<< std::endl;
                    osg::Vec3d ip = hitList.front().getWorldIntersectPoint();
                    osg::Vec3d np = hitList.front().getWorldIntersectNormal();
                    if (up*np>0.0) up = np;
                    else up = -np;
                    _eye = ip+up*_height;
                    lv = up^sv;
                    computePosition(_eye,_eye+lv,up);
                    return true;
                }
            }
            
            //第二次没有检测到碰撞,那么进行第三次碰撞检测
            osg::Vec3d dp = lfp;
            dp -= getUpVector(cf)* (2*_modelScale);
            iv.reset();
            osg::ref_ptr<osg::LineSegment> segFall = new osg::LineSegment;
            segFall->set(lfp,dp);
            iv.addLineSegment(segFall.get());

            _node->accept(iv);
            if (iv.hits())
            {
                osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segFall.get());
                if (!hitList.empty())
                {
                    //notify(INFO) << "Hit terrain on decent ok"<< std::endl;
                    osg::Vec3d ip = hitList.front().getWorldIntersectPoint();
                    osg::Vec3d np = hitList.front().getWorldIntersectNormal();
                    if (up*np>0.0) up = np;
                    else up = -np;
                    _eye = ip+up*_height;
                    lv = up^sv;
                    computePosition(_eye,_eye+lv,up);
                    return true;
                }
            }
            lv *= (_velocity*dt);   
            _eye += lv;
        }
        return true;
    }

    五 小结
    碰撞检测非常复杂,涉及包围体和相交检验等各方面的知识,上面只是碰撞检测最简单的应用。以上思想只是个人的分析,并未得到验证,细节也并未处理,希望各位大侠给与指导。

    再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

  • 相关阅读:
    后端——框架——持久层框架——Mybatis——补充——config配置文件中setting各项含义——待补充
    后端——框架——持久层框架——Mybatis——补充——pageHelper(分页)插件
    后端——框架——持久层框架——Mybatis——补充——commonMapper(通用Mapper)插件——待补充
    spring当中定时任务出现的问题
    mysql中死锁的出现以及解决情况
    spring boot启动原理
    spring boot方式实现aop
    使用spring boot的方式实现spring的拦截器(附加xml实现方式)
    mybatis使用注解的方式进行增删改查基本的操作
    spring静态属性的注入
  • 原文地址:https://www.cnblogs.com/skiwnchiwns/p/10345418.html
Copyright © 2020-2023  润新知