Ogre3D嵌入Qt框架

  按照經典的Qt程序結構,應該有一個從QMainWindow繼承而來的MainWindow,讓它做爲主窗口,然後子類化一個QWidget,它做爲主窗口的"中心掛件",能過封裝Ogre的部分功能,實現用Ogre對該窗體的繪製。首先,如何把Ogre這個引擎發動,不斷驅動其進行工作。Qt也需要告訴Ogre如何把渲染的內容畫到指定的窗口中去,以及用哪種方式更新窗口中的內容。

         當鍵盤或鼠標消息來的時候,如何通知Ogre進行響應。從Ogre這邊來看,就是如何把Ogre的功能,分佈到Qt的各個部分。而且與一般的ogre程序不同,不是進入到連續的循環中(一般的ogre程序中,通過執行mRoot->startRendering();語句進入一個不停渲染循環,通過預先安插好的幀偵聽器來對消息進行響應,對程序邏輯進行處理)而可以是“必要時”對窗口進行更新。而且與一般ogre程序不同,由於Qt自身可以檢測輸入設備消息,因此,OIS不再需要。
         把Ogre中的內容嵌入到Qt,從形式來看可以許多種,也就是說可以把相關Ogre的部分拆成不同部分,按照作者的需要封裝在Qt中的不同部分。比如,Ogre中描述抽象的“引擎”概念的部分(Root等),因爲我們想一但應用程序啓動,就應該讓Ogre引擎啓動了,那麼這些部分可以用QApplication封裝,而且RenderWindow,與Qt中的QWidget概念上是關聯的,所以就用QWidget來封裝。出於簡單的原因,我把Ogre都封裝從QWidget繼承而來的OgreView中了。很顯然,主要考慮OgreView就可以了。
class  OgreView  :  public  QWidget    
{    
    Q_OBJECT    
        
public:    
    OgreView(QWidget*  parent  );    
    ~OgreView();    
    //QSize  minimumSizeHint()  const;    
    //QSize  sizeHint()  const;    
protected:    
    void  setupView()//創建Ogre使用的內容,場景內容;    
        void  update();//通過它,手動更新場景內容    
    void  setupResources();//    
    void  createScene();    
    void  createLight();    
    void  resizeEvent(QResizeEvent*  evt);//窗口可能縮放    
    void  timerEvent(QTimerEvent*  evt);//可以設一時鐘來更新窗口    
    void  paintEvent(QPaintEvent*  evt);//呵,當然得處理了    
    //消息響應    
    void  keyPressEvent(QKeyEvent*  evt);    
    void  keyReleaseEvent(QKeyEvent*  evt);    
    void  mousePressEvent(QMouseEvent*  evt);    
    void  mouseReleaseEvent(QMouseEvent*  evt);    
    void  mouseMoveEvent(QMouseEvent*  evt);    
    void  wheelEvent(QWheelEvent*  evt);    
    
    //有關Ogre    
    Ogre::RenderWindow*  mRenderWindow;    
    Ogre::SceneManager*  mSceneMgr;    
    Ogre::Camera*  mCamera;    
    Ogre::Viewport*  mVp;    
    Ogre::Root*  mRoot;    
    Ogre::Light*  mainLight;    
    Ogre::Entity*  mainEnt;    
    Ogre::SceneNode*  mainNode;    
    //一些控制變量,沒有完全列出    
    Ogre::Vector3  mDirection;    
    Ogre::Real  mRotate;    
    
};    
//cpp文件中的內容(部分)    
OgreView::OgreView(QWidget*  parent) : QWidget(parent,Qt::WFlags(Qt::MSWindowsOwnDC))    
{    
    mRenderWindow  =  NULL;    
    mSceneMgr  =  NULL;    
    mVp  =  NULL;    
    mainEnt  =  NULL;    
    mainNode  =  NULL;    
    //....還有一些控制變量的初始化    
    setupResources();    
}    
OgreView::~OgreView()    
{    
    //  destroy  Viewport  and  RenderWindow    
    if(  mVp  )    
    {    
        mRenderWindow->removeViewport(mVp->getZOrder());    
        mVp  =  0;    
    }    
    
    Ogre::Root::getSingleton().detachRenderTarget(mRenderWindow);    
    mRenderWindow  =  0;    
    
    if(mRoot  !=  NULL){    
        delete  mRoot;    
        mRoot  =  0;    
    }    
}    
void  OgreView::setupResources()    
{    
    mRoot  =  new  Ogre::Root();    
    Ogre::ConfigFile  cf;    
    cf.load("resources.cfg");    
    
    Ogre::ConfigFile::SectionIterator  seci  =  cf.getSectionIterator();    
    Ogre::String  secName,  typeName,  archName;    
    while(seci.hasMoreElements())    
    {    
        secName  =  seci.peekNextKey();    
        Ogre::ConfigFile::SettingsMultiMap*  settings  =  seci.getNext();    
        Ogre::ConfigFile::SettingsMultiMap::iterator  i;    
        for(i=settings->begin();  i!=settings->end();  ++i){    
            typeName  =  i->first;    
            archName  =  i->second;    
            Ogre::ResourceGroupManager::getSingleton().
    addResourceLocation(archName,  typeName,  secName);    
        }    
    }    
    
    if(!mRoot->restoreConfig())    
    {    
        mRoot->showConfigDialog();    
    }    
    mRoot->initialise(false);    
    //以上都是從Ogre普通程序照搬    
}    
//沒啥說的,代碼比註釋更明白    
void  OgreView::createScene()    
{    
    mainEnt  =  mSceneMgr->createEntity("Head",  "ogrehead.mesh");    
    mainNode  =  mSceneMgr->getRootSceneNode()->createChildSceneNode();    
    mainNode->attachObject(mainEnt);    
}    
void  OgreView::createLight()    
{    
    
        mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5,  0.5,  0.5));    
        mainLight  =  mSceneMgr->createLight("MainLight");    
        mainLight->setPosition(20,80,50);    
}    
void  OgreView::setupView()    
{    
        if(mRenderWindow)    
                return;    
    //createRenderWindow,當然必須得自己手工建窗口了,把窗口句柄扒出來....    
    
    Ogre::NameValuePairList  params;    
    params["externalWindowHandle"]  =  Ogre::StringConverter::toString((size_t)(HWND)winId());    
    mRenderWindow  =  mRoot->createRenderWindow("View",  width(), height(),  false,  params);    
    //SceneManager    
    mSceneMgr  =  mRoot->createSceneManager(Ogre::ST_GENERIC);    
    //setup  camera  &  viewport      
    mCamera  =  mSceneMgr->createCamera("PlayerCam");    
    mCamera->setPosition(Ogre::Vector3(0,0,80));    
    mCamera->lookAt(Ogre::Vector3(0,0,-300));    
    mCamera->setNearClipDistance(5);    
    mVp  =  mRenderWindow->addViewport(mCamera);    
    mVp->setBackgroundColour(Ogre::ColourValue(0,  0.0,  0.0,  1));    
    mCamera->setAspectRatio(Ogre::Real(mVp->getActualWidth())  /  
       Ogre::Real(mVp->getActualHeight()));    
    //resource    
    Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();    
    createScene();    
    createLight();    
    startTimer(2);    
}    
void  OgreView::paintEvent(QPaintEvent  *evt)    
{    
    Q_UNUSED(evt);    
        if(mRenderWindow  ==  NULL)    
                setupView();    
    update();    
}    
void  OgreView::timerEvent(QTimerEvent*  evt)    
{    
    Q_UNUSED(evt);    
    update();    
    
}    
void  OgreView::update()    
{    
    //手工更新場景內容,而不是進入到連續的循環中    
    if(mRenderWindow  !=  NULL){    
        mRoot->_fireFrameStarted();    
        mRenderWindow->update();    
        
        mCamera->moveRelative(mDirection);    
        mCamera->yaw(Ogre::Radian(angleX));    
        mCamera->pitch(Ogre::Radian(angleY));    
        
        mRoot->_fireFrameEnded();    
    }    
}    
void  OgreView::resizeEvent(QResizeEvent  *evt)    
{    
    Q_UNUSED(evt);    
    if  (mRenderWindow  !=  NULL){    
        mRenderWindow->windowMovedOrResized();    
        mCamera->setAspectRatio(Ogre::Real(mVp->getActualWidth())  /  Ogre::Real(mVp->getActualHeight()));    
    }    
}    
void  OgreView::keyPressEvent(QKeyEvent*  evt)    
{    
    if(mainEnt  !=  NULL  &&  mainNode  !=  NULL){    
        switch(evt->key()){    
        case  Qt::Key_W:    
        case  Qt::Key_Up:    
            rotX  =  -0.1;    
            mainNode->pitch(Ogre::Radian(rotX));    
            break;    
        case  Qt::Key_S:    
        case  Qt::Key_Down:    
            rotX  =  0.1;    
            mainNode->pitch(Ogre::Radian(rotX));    
            break;    
        case  Qt::Key_A:    
        case  Qt::Key_Left:    
            rotY  =  -0.1;    
            mainNode->yaw(Ogre::Radian(rotY));    
            break;    
        case  Qt::Key_D:    
        case  Qt::Key_Right:    
            rotY  =  0.1;    
            mainNode->yaw(Ogre::Radian(rotY));    
            break;    
        }    
    }    
}    
void  OgreView::mousePressEvent(QMouseEvent*  evt)    
{    
    if(evt->button()  ==  Qt::LeftButton)    
        mouseLeftPressed  =  true;    
    if(evt->button()  ==  Qt::RightButton){    
        mouseRightPressed  =  true;    
        mousePos  =  Ogre::Vector2(evt->x(),  evt->y());    
    }    
    if(evt->button()  ==  Qt::MidButton)    
        mouseMiddleBtn  =  true;    
}    
void  OgreView::wheelEvent(QWheelEvent*  evt)    
{    
    mDirection.z  =  -evt->delta()/12;    
    update();    
    mDirection.z  =  0;    
}    



發佈了3 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章