Archie OSG Step By Step④ MFC+OSG添加事件

本文以第三课MFC+OSG框架为基础进行讨论。参考CWorld《基于MFC(QT)的OSG的自定义事件》

source下载链接

首先找到资源视图,添加菜单,如果没有资源视图,选择“视图→其他窗口→资源视图”,添加菜单项替换场景\t(&R), 在菜单编辑器中修改ID为IDM_REPLACE_SCENE


右击菜单项,选择添加事件处理程序


添加编辑

菜单单击属于一种事件,我们应该针对事件设置回调函数,但是OSG是通用渲染引擎,不会为了MFC、Qt提供菜单、按钮这样的事件类型。所以我们只能自定义事件。

基本思路:
在MFC中,存在两个线程(MFC+UI)线程和OSG线程,简单的我们可以认为存在两个事件队列,即MFC的事件队列和OSG的事件队列,我们的思路就是在菜单响应函数里,把我们的自定义事件压入OSG的事件队列,然后在OSG的渲染线程里进行处理。具体思路如下图


如何自定义事件

下面我们以替换模型和给模型添加包围盒为例,来谈谈如何结合mfc+osg来实现自定义事件,压入事件队列,如何处理自定义事件。

添加自定义事件类,我命名为CArchieEventAdapter,继承自 public osg::Referenced

以下代码至添加事件处理类框架类之前都在CArchieEventAdapter.h文件中添加

#include 
#include 
#include 
#include #include

首先定义事件枚举类型

enum MFC_EVENT_TYPE
{NONE = 0,BOUNDINGBOX = 1,//包围盒REPLACE = 2//替换场景
};

给CArchieEventAdapter添加变量,并设置构造函数设置为NONE添加函数SetEventType。

MFC_EVENT_TYPE m_eventType;//事件类型
CArchieEventAdpater::CArchieEventAdpater(void)  //这个在CArchieEventAdapter.cpp文件
{m_eventType = NONE;
}void SetEventType(MFC_EVENT_TYPE eventType){ m_eventType = eventType;}//内联函数

添加事件处理框架类CArchieHandler

#include
#include 
#include
#include 
#include 
#include #include #include 
#include 
#include "ArchieEventAdpater.h"


 

class CArchieHandler :public osgGA::GUIEventHandler

添加保护乘员变量
protected:osg::ref_ptr  root;

修改构造函数为
public:CArchieHandler( osg::Group* rt ): root(rt){}


添加事件处理:重载函数handle()

virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa);

bool CArchieHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{switch(ea.getEventType()){case osgGA::GUIEventAdapter::KEYDOWN:break;case osgGA::GUIEventAdapter::FRAME:break;case osgGA::GUIEventAdapter::USER:{const CArchieEventAdpater* adapter = dynamic_cast(ea.getUserData());switch(adapter->m_eventType){case NONE:break;case REPLACE:root->removeChild(0,1);root->addChild(osgDB::readNodeFile("glider.osg"));break;case BOUNDINGBOX:{osg::Node *node=root->getChild(0);root->addChild(createBoudingShpere(node));break;}default:break;} // end case adapter->m_eventTypebreak;} // end case USERdefault:break;}return false;
}

其中添加包围盒函数为

osg::ref_ptr createBoudingShpere(osg::Node * node)
{osg::ref_ptr geode = new osg::Geode();//计算模型的包围盒const osg::BoundingSphere bs = node->getBound();//得到球体半径float radius =bs.radius();//设置精细度osg::ref_ptr hints = new osg::TessellationHints;hints->setDetailRatio(0.5f);osg::Vec3 v = bs._center;osg::ShapeDrawable *shapeBall=new osg::ShapeDrawable(new osg::Sphere(v,radius),hints.get());shapeBall->setColor(osg::Vec4(1.0f,1.0f,0.5f,0.3f));geode->addDrawable(shapeBall);osg::ref_ptr stateset = geode->getOrCreateStateSet();//关闭光照stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);stateset->setMode(GL_BLEND, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);//设置透明渲染stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);return geode.release();}

 

 

有了事件处理函数还不够,必须添加到viewer的事件处理队列中

在CoreOSG.cpp中添加包含文件

#include "ArchieHandler.h"

添加如下代码

//添加事件mViewer->addEventHandler(new CArchieHandler(mRoot.get()));


此时就关联在了一起

void CCoreOSG::InitCameraConfig(void)
{// 局部变量存放窗口矩形.......... osg::ref_ptr camera = new osg::Camera;..........          mViewer->setSceneData(mRoot.get());//添加事件mViewer->addEventHandler(new CArchieHandler(mRoot.get()));// 实现VIEWERmViewer->realize();
}



我们可以在我们的CView里把事件压入OSG的事件队列,并且我们的基本事件类型都是GUIEventAdapter::User类型的,然后在USER类型里,我们再进行我们具体的事件分类,即是包围盒事件还是替换模型事件等,具体的压入事件方法如下:

View.cpp

// CMy3DVisionView
#include "ArchieEventAdpater.h"

void CMy3DVisionView::OnReplaceScene()
{CArchieEventAdpater *myType = new CArchieEventAdpater();myType->SetEventType(REPLACE);mOSG->GetViewer()->getEventQueue()->userEvent(myType);
}

void CMy3DVisionView::OnAddBoundingbox()
{CArchieEventAdpater *myType = new CArchieEventAdpater();myType->SetEventType(BOUNDINGBOX);mOSG->GetViewer()->getEventQueue()->userEvent(myType);
}




本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部