惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
The Blog of Author Tim Ferriss
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
MongoDB | Blog
MongoDB | Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
AI
AI
NISL@THU
NISL@THU
AWS News Blog
AWS News Blog
V
Visual Studio Blog
博客园 - 三生石上(FineUI控件)
C
Cyber Attacks, Cyber Crime and Cyber Security
P
Privacy & Cybersecurity Law Blog
S
Schneier on Security
PCI Perspectives
PCI Perspectives
H
Hackread – Cybersecurity News, Data Breaches, AI and More
T
Troy Hunt's Blog
云风的 BLOG
云风的 BLOG
N
News and Events Feed by Topic
Know Your Adversary
Know Your Adversary
F
Fortinet All Blogs
Spread Privacy
Spread Privacy
P
Proofpoint News Feed
Jina AI
Jina AI
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
WordPress大学
WordPress大学
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V
Vulnerabilities – Threatpost
P
Privacy International News Feed
T
Tor Project blog
S
Security Affairs
S
Securelist
F
Full Disclosure
D
Docker
酷 壳 – CoolShell
酷 壳 – CoolShell
Martin Fowler
Martin Fowler
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
SecWiki News
SecWiki News
P
Palo Alto Networks Blog
Apple Machine Learning Research
Apple Machine Learning Research
N
News and Events Feed by Topic
Recorded Future
Recorded Future
The Hacker News
The Hacker News
Google Online Security Blog
Google Online Security Blog
Stack Overflow Blog
Stack Overflow Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
I
Intezer
Security Latest
Security Latest
Scott Helme
Scott Helme
U
Unit 42
Y
Y Combinator Blog
The GitHub Blog
The GitHub Blog

博客园 - sharewind

zookeepr 单机伪集群配置 Java泛型通配符extends与super 简单介绍相册网站的架构 Javascript 动态加载 CSS STYLE 元素 DOS:先进入 bat 文件的路径,然后执行 bat 文件,然后回到当前目录收藏 (转载)简洁、明晰!数据库设计三大范式应用实例剖析 (转载)tomcat5下jsp出现getOutputStream() has already been called for this 解决eclipse+myeclipse的Processing Dirty Regions错误 Eclipse格式化代码时不换行 与 自动换行 JavaScript笔记 - 对象继承的几种方式 (转载)oracle 10g 安装完成后,无法登陆EM的解决办法 VS 2008 下载及序列号 Windows系统必备的30个免费开源软件 (转载) VC常见数据类型转换详解 java中关于时间日期操作的常用函数 How To Connect to a SQL Server 2000 Named Instance with JDBC JavaScript对象与数组参考大全 SQL Server数据库开发的二十一条军规 数据库经典文章!(必备)
摄像机 碰撞检测
sharewind · 2008-06-02 · via 博客园 - sharewind

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

   

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

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

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

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

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

三 重要的类和函数

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;
}

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