攝像機 碰撞檢測

來源:互聯網
上載者:User
(轉載)碰撞檢測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;
}

五 小結
碰撞檢測非常複雜,涉及包圍體和相交檢驗等各方面的知識,上面只是碰撞檢測最簡單的應用。以上思想只是個人的分析,並未得到驗證,細節也並未處理,希望各位大俠給與指導。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.