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

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

source下载链接

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

Archie OSG Step By Step④ MFC+OSG添加事件_第1张图片

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

Archie OSG Step By Step④ MFC+OSG添加事件_第2张图片

添加编辑

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

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


如何自定义事件

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

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

Archie OSG Step By Step④ MFC+OSG添加事件_第3张图片

以下代码至添加事件处理类框架类之前都在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);
}



你可能感兴趣的:(Archie OSG Step By Step④ MFC+OSG添加事件)