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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章