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

推荐订阅源

S
Security Affairs
S
Schneier on Security
N
News | PayPal Newsroom
T
Threatpost
Cloudbric
Cloudbric
H
Heimdal Security Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Google Online Security Blog
Google Online Security Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Spread Privacy
Spread Privacy
V
Vulnerabilities – Threatpost
The Last Watchdog
The Last Watchdog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
L
LINUX DO - 最新话题
P
Proofpoint News Feed
C
CXSECURITY Database RSS Feed - CXSecurity.com
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Apple Machine Learning Research
Apple Machine Learning Research
NISL@THU
NISL@THU
Application and Cybersecurity Blog
Application and Cybersecurity Blog
The Hacker News
The Hacker News
O
OpenAI News
人人都是产品经理
人人都是产品经理
C
Cyber Attacks, Cyber Crime and Cyber Security
C
Check Point Blog
C
Cisco Blogs
GbyAI
GbyAI
J
Java Code Geeks
L
LangChain Blog
I
Intezer
T
Tailwind CSS Blog
有赞技术团队
有赞技术团队
MyScale Blog
MyScale Blog
美团技术团队
The Register - Security
The Register - Security
Help Net Security
Help Net Security
WordPress大学
WordPress大学
Y
Y Combinator Blog
T
Tor Project blog
M
MIT News - Artificial intelligence
爱范儿
爱范儿
TaoSecurity Blog
TaoSecurity Blog
V
Visual Studio Blog
T
Threat Research - Cisco Blogs
P
Palo Alto Networks Blog
月光博客
月光博客
T
Tenable Blog
S
Securelist
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
D
DataBreaches.Net

博客园 - 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;
}

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