您的位置:首页 > 其它

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

2013-01-01 22:45 465 查看
本文以第三课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 <osgDB/ReadFile>
#include <osgGA/GUIEventHandler>
#include <osgViewer/Viewer>
#include <iostream>

#include<osg/Referenced>

首先定义事件枚举类型

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<osg/Referenced>
#include <osg/Node>
#include<osg/Geode>
#include <osg/Group>
#include <osg/ShapeDrawable>
#include <osg/ref_ptr>

#include <osgGA/GUIEventHandler>

#include <osgDB/WriteFile>
#include <osgDB/ReadFile>
#include "ArchieEventAdpater.h"


 

class CArchieHandler :
public osgGA::GUIEventHandler


添加保护乘员变量
protected:
osg::ref_ptr<osg::Group>  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<const CArchieEventAdpater*>(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_eventType
break;
} // end case USER
default:
break;

}
return false;
}


其中添加包围盒函数为

osg::ref_ptr<osg::Geode> createBoudingShpere(osg::Node * node)
{
osg::ref_ptr<osg::Geode> geode = new osg::Geode();

//计算模型的包围盒
const osg::BoundingSphere bs = node->getBound();

//得到球体半径
float radius =bs.radius();

//设置精细度
osg::ref_ptr<osg::TessellationHints> 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<osg::StateSet> 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<osg::Camera> camera = new osg::Camera;

..........
mViewer->setSceneData(mRoot.get());

//添加事件 mViewer->addEventHandler(new CArchieHandler(mRoot.get()));// 实现VIEWER
mViewer->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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: