Ogre3D嵌入Qt框架 之 小结

    技术2022-05-20  45

    按照经典的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, ¶ms); //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;}


    最新回复(0)