第37.1节 框选-绘制框选框_杨石兴的博客-程序员信息网

技术标签: osg  osgChina站长文集  OpenSceneGraph  

首先祝大家国庆快乐

本节内容

本节开始介绍鼠标选择的操作。正常情况下我们都会在场景中使用鼠标框选一些物体。本节我们绘制了框选框,程序启动后,按住键盘上的左CTRL键,然后鼠标在场景中拖动,会出来一个白色的框,符合框选的习惯。如下图所示:
在这里插入图片描述
本节代码在如下网盘中,根据章节编号有对应附件,请使用浏览器打开,平时遇到问题或加群也可以加我微信:13324598743:
【击此打开网盘资源链接】

实现要点

要点只有两个,其它均为正常的绘制和逻辑处理:

  1. 在点下左CTRL的时候,鼠标拖动时要在框选的状态,此时场景的操作器就不起作用了。不能一边选着,场景随着鼠标的拖动还转着,那就不行。此处只需要在事件中返回true,后面的事件处理器就不再处理该事件了。场景也就不转动了 这是个很隐蔽但是又很重要的知识点。具体实现参见MyEvent中的handle,注释较为详尽。
  2. 在屏幕表面绘制一个白色的框要用到HUD,HUD的初始化需要知道当前场景的窗口是多大,而当前的窗口是在viewer.realize之后才创建的,因此需要在viewer.realize之后获取viewport参数之后,再创建HUD中的相机,设置setProjectionMatrix。

以下为全部代码

#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osg/Camera>
#include <osgGA/GUIEventHandler>

//结点的掩码,显示与隐藏
#define NODE_SHOW ~0x0
#define NODE_HIDE 0x0

//选择框做为一个全局变量,使用起来方便
osg::Geometry* g_geomSelectBox = new osg::Geometry;

//
osg::Camera* createHUD(osg::Viewport* vp)
{
    
    osg::Camera* camera = new osg::Camera;

    //设置投影矩阵为正交投影
    camera->setProjectionMatrix(osg::Matrix::ortho2D(0, vp->width(), 0, vp->height()));

    //设置其观察矩阵为单位矩阵,且不改变,该相机永远显示,也不用参与拣选
    camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
    camera->setViewMatrix(osg::Matrix::identity());

    //只清空深度缓存,使得其显示内容可以以主相机为背景
    camera->setClearMask(GL_DEPTH_BUFFER_BIT);

    //最后渲染,因为需要以主相机显示的内容为背景
    camera->setRenderOrder(osg::Camera::POST_RENDER);

    //不需要响应事件
    camera->setAllowEventFocus(false);

    //绘制选择框
    osg::Geode* gnode = new osg::Geode;
    camera->addChild(gnode);

    gnode->addDrawable(g_geomSelectBox);
    //设置透明
    osg::StateSet* ss = gnode->getOrCreateStateSet();
    ss->setMode(GL_BLEND, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
    ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
    ss->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);

    //设置顶点
    osg::Vec3Array* vertices = new osg::Vec3Array;
    float depth = - 0.1;
    vertices->push_back(osg::Vec3(0, 0, depth));
    vertices->push_back(osg::Vec3(100, 0, depth));
    vertices->push_back(osg::Vec3(100, 100, depth));
    vertices->push_back(osg::Vec3(0, 100, depth));
    g_geomSelectBox->setVertexArray(vertices);

    //设置颜色
    osg::Vec4Array* color = new osg::Vec4Array;
    color->push_back(osg::Vec4(0.8, 0.8, 0.8, 0.2));
    g_geomSelectBox->setColorArray(color, osg::Array::BIND_OVERALL);

    //绘制盒子
    g_geomSelectBox->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));

    return camera;
}

class MyEvent : public osgGA::GUIEventHandler
{
    
public:
    MyEvent() :osgGA::GUIEventHandler(),
        _xStart(0),
        _yStart(0)
    {
    
    }

    virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
    {
    
        //左ctrl按着,又鼠标点击,则进入绘制状态
        if (ea.getEventType() == ea.PUSH) //
        {
    
            //判断左CTRL键是否按下
            if (ea.getModKeyMask() == ea.MODKEY_LEFT_CTRL)
            {
    
                _xStart = ea.getX();
                _yStart = ea.getY();
                //清空之前绘制的结果,这里仅隐藏即可
                g_geomSelectBox->setNodeMask(NODE_HIDE);

                //返回真代表后续事件处理器包括操作器不再处理该事件,就实现了拖动时场景不动
                return true;
            }
        }


        //左ctrl点下时,进入到选择状态,开始绘制选择框,且操作器不再处理鼠标拖动事件
        if (ea.getEventType() == ea.DRAG) //鼠标拖动,拖动是鼠标按键按下的时候移动鼠标
        {
    
            //判断左CTRL键是否按下
            if (ea.getModKeyMask() == ea.MODKEY_LEFT_CTRL)
            {
    
                //开始绘制,调整顶点参数就可以
                g_geomSelectBox->setNodeMask(NODE_SHOW);

                //获取顶点、更新顶点
                osg::Vec3Array* vertices = (osg::Vec3Array*)g_geomSelectBox->getVertexArray();
                int xEnd = ea.getX();
                int yEnd = ea.getY();
                float depth = -0.1;
                vertices->at(0).set(_xStart, _yStart, depth);
                vertices->at(1).set(xEnd, _yStart, depth);
                vertices->at(2).set(xEnd, yEnd, depth);
                vertices->at(3).set(_xStart, yEnd, depth);

                //重绘
                g_geomSelectBox->dirtyDisplayList();

                //返回真代表后续事件处理器包括操作器不再处理该事件,就实现了拖动时场景不动
                return true;
            }
        }

        return false;
    }

    int _xStart, _yStart;
};


int main()
{
    
    osgViewer::Viewer viewer;
   
    osg::Group* root = new osg::Group;

    root->addChild(osgDB::readNodeFile("cow.osg"));

    viewer.setSceneData(root);
    viewer.realize();

    //realize之后,上下文已经被初始化,可以获得视口大小
    //在此处获得视口大小是为了创建HUD时使其视口大小与创建的一致
    osg::Viewport* vp = viewer.getCamera()->getViewport();
    root->addChild(createHUD(vp));

    viewer.addEventHandler(new MyEvent);

    return viewer.run();
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/FreeSouthS/article/details/120576785

智能推荐

思科配置系统日志服务器配置,思科交换机路由器配置日志服务器脚本_杜路辉的博客-程序员信息网

日志服务hostname(config)#logging onhostname(config)#logging host {ip_address | host_name}hostname(config)#logging trap security_levelhostname(config)#logging source-interface interface_type interface_#hos...

5GNR漫谈11:PRACH随机接入信道(1)_5g prach_guet208的博客-程序员信息网

5GNR漫谈11:PRACH随机接入信道(一)在5GNR漫谈2中我们知道,终端开机后获取小区广播消息,广播消息里面包含了本小区可利用的资源,到此为止还只是个受众,还没有与小区进行交流,也即终端此时仅是解调了基站发出来的广播下行信号,基站开机后就在那里发送本小区资源信息,告诉周围覆盖范围内的终端,它是该地方的老大,是为人民服务的,大家需要的时候就找它,但是不要随随便便的来,领导都很忙,大家要按规章纪律来,也即要在广播消息里允许的时间地点(频率)来,它才能接待新来客,其它时间基站要处理业务,要闭门谢客的。只有

从window中的eclipse中提交jar包到yarn框架运行,出现Exception from container-launch: org.apache.hadoop.util.Shell$_alitao-2014的博客-程序员信息网

原因一:是jar包classpath的问题,把所有需要的hadoop jar包全部加入yarn-site.xml 中的到'yarn.application.classpath' 里面。代码如下:(确保你已经设定了HADOOP_HOME这个环境变量) yarn.application.classpath %HADOOP_HOME%\etc\hadoop, %HADOO

谷歌浏览器无法从该网站添加应用、扩展程序和用户脚本_王福强的博客-程序员信息网

使用谷歌最常见得就是这个页面了因为我们访问不到谷歌服务,导致无法使用第三方提供的谷歌插件本文主要介绍一波以开发者模式添加谷歌插件到谷歌浏览器的骚操作1.下载扩展程序国内插件市场:https://www.chromefor.com/里面有丰富的插件供你下载2.将.crx结尾的插件文件修改为可用的压缩包如果下载的文件是.crx结尾的文件则将后缀改为rar或者zi...

中的句子_pavingthefuture的博客-程序员信息网

摘至《think c++》///////////////////////////////////建立公共接口的唯一的理由是使得它能对于每个不同的子类有不同的表示。它建立一个基本的格式,由此可以知道什么是对于所有派生类公共的。当希望通过公共接口操作一组类时就创建抽象类。///////////////////////////////////////• C + +程序员的进步C程序员似乎可以用三步进入C

随便推点

微信小程序注册流程图文详解_谷哥的小弟的博客-程序员信息网

本文以图文形式详细记录微信小程序的注册流程及其注意事项

NOIP模拟题 2016.11.14 [动态规划] [线段树优化DP] [字符串的复制粘贴DP]_JacquesdeH的博客-程序员信息网

复制&粘贴2(A.c/cpp/pas/in/out) (Time Limit:1s Memory Limit:256MB) 【Description】 文本编辑器的一个最重要的机能就是复制&粘贴。JOI社现在正在开发一款能够非常高速地进行复制&粘贴的文本编辑器,作为JOI社一名优秀的程序猿,你担负起了复制&粘贴功能的测试这一核心工作。整个JOI社的命运都系在你的身上,因此你无论如何都想写出一个

Python3 网易有道词典结合PyInstaller,tkinter制作一个简单的中英文翻译exe文件_xudailong_blog的博客-程序员信息网

来自徐代龙的博客,python3 gui编程练习,结合有道词典api,结合tkinter,结合PyInstaller生成exe文件,源代码上传到github上 一: 有道词典的API接口爬取: 二:tkinter 各种控件的使用: 三:PyInstaller 打包成exe文件,直接在桌面上进行应用:

Python每日一记19>>>无监督学习K-Means聚类_教练 我想学编程的博客-程序员信息网

令人惊讶的是,尽管我们的世界几乎被数据所淹没,但很大一部分是未经标注未被整理过的,这意味着这些数据对于大多数目前的监督式学习来说是不可用的。以上,反映出监督学习的局限性也突出无监督学习的重要性和发展前景,即便如此,目前而言,任何无监督学习的准确性和有效性也达不到监督学习的效果。在介绍无监督学习之前,先介绍数据预处理。1、数据预处理通用代码from sklearn.preprocessin...

纳米压印技术的学习_秃头美少女wxy的博客-程序员信息网

1.应用领域:宏观方面如印章、刻录光盘;微观方面如制备晶体管和集成电路。由集成电路加工成的计算机构成现代信息社会的基础。广泛应用于图案转移技术中,其中最多的为光盘的制备。2.优点:微纳复制技术只需要制备一个模板就可以廉价、快速的加工出许多复制品3.光刻技术的诞生:摩尔的大胆预测:摩尔定律:“每个芯片上集成的元件数平均每18个月将翻一番”在光学光刻中,通过减少特征尺寸得到...

构建Scala的Maven项目_风行者之倾覆天下的博客-程序员信息网

spark的scala项目Maven构建和使用一、使用spark-sql使用spark-sql --master yarn --num-executors 30 --executor-memory 12g二、建立项目1.建立Maven项目:吧java文件夹重命名为scala文件夹2.修改xxx.xml配置3.删除./idea下文件 sca

推荐文章

热门文章

相关标签