AD

Integrating Ogre3D 1.7.4 with Qt 4.8.1


.Introduction


      Many people discussed about how to integrate with Ogre3D engine and Qt libraries. Here are some implements,including 3rd add-on named QtOgreFramework at Ogre3D official site, a framework named QtOgre on Ogre Forums, and some articles.

   
      According these articles and add-on souce, I try to integrate Ogre3D in Qt application by rendering Ogre3D content on Qt QWidge.



.Environment


      I use Ogre3D version 1.7.4 , Qt libraries version 4.8.1 ,and building source code on Visual studio C++ 2010.
  • Ogre3D v1.7.4
  • Qt Libraries v4.8.1
  • Visual studio c++ 2010

.Implement


      There are four steps to integrate Ogre3D in Qt.
  1. Create a Qt widget for Ogre3D, called OgreWidget
  2. Initialize Ogre3D
  3. Using Ogre3D to update OgreWidget
  4. Using OgreWidget

1.Create a Qt widget for Ogre3D, called OgreWidget
 
      First of all, we should implement the qt widget for rendering content by Ogre3D. In this widget we should overwrite some event handler function like resizeEvent, paintEvent, The widget(OgreWidget) will be like this.

class OgreWidget : public QWidget
{
 Q_OBJECT
public:
 OgreWidget (QWidget* parent = 0);
 ~ OgreWidget ();

 virtual void resizeEvent(QResizeEvent* evt);
 virtual void timerEvent(QTimerEvent* evt);
 virtual void paintEvent(QPaintEvent* evt);
protected:
 Ogre::Root *mOgreRoot;
 Ogre::RenderWindow *mOgreWindow;
 Ogre::Camera *mCamera;
 Ogre::Viewport *mViewport;
 Ogre::SceneManager *mSceneMgr;
 Ogre::Light* mMainLight;
 Ogre::SceneNode* mHeadNode;
 Ogre::RenderSystem *mRenderSystem;
}


2.    Initialize OgreWidget
 
      The step initializing OgreWidget is almost the same with Ogre3D's demonstration , what we need is just to create root, setup render system, and load resources. However, there are something need to be concerned, we have to pass Qt widget handle to Ogre3D when creating Ogre3D render window.

.All of steps to Initialize OgreWidget

OgreWidget::OgreWidget(QWidget *parent)
:QWidget(parent){
 createOgreRoot();
 assert(setupOgreRenderSystem() == SUCCESS);
 createOgreRenderWindow();
 initOgreScene();
}

OgreWidget::~ OgreWidget (){
 release();
}

.create ogre root object
void OgreWidget::createOgreRoot(){
 mOgreRoot = new Ogre::Root("plugins.cfg", "ogre.cfg",  "ogre.log"); 
}

.setup Ogre3D Render System
int OgreWidget::setupOgreRenderSystem(){
 Ogre::RenderSystemList::const_iterator renderers;
 renderers = mOgreRoot->getAvailableRenderers().begin();

 while(renderers != mOgreRoot->getAvailableRenderers().end()){
  Ogre::String rName = (*renderers)->getName();
  if (rName == "Direct3D9 Rendering Subsystem"){
   mOgreRoot->setRenderSystem(*renderers);
    return SUCCESS;
  }
  renderers++;
 }
 return FAILED;
}

.create Ogre3D Render Window


      There are three points in this step.
  • Initialize Ogre3D without creating window
  • Set OgreWiget WId to Ogre3D parameter externalWindowHandle for creating render window
  • Set OgreWidget size to Ogre3D render window

void OgreWidget:: createOgreRenderWindow(){
 Ogre::String winHandle;
 Ogre::NameValuePairList params;

 // 1. initialize without creating window
 mOgreRoot->initialise(false); 

 //2. pass OgreWidget WId to parameter "externalWindowHandle" for creating renderwindow
 winHandle = Ogre::StringConverter::toString((size_t)(HWND) winId());
 params["externalWindowHandle"] = winHandle;

 //3. set OgreWidget size to create render window
 mOgreWindow = mOgreRoot->createRenderWindow( "QtOgreWidget_RenderWindow",
  width(),
  height(),
  true,
  &params );
}

.Initializng Ogre3D Scene

void OgreWidget::initOgreScene(){ 
 Ogre::SceneType scene_manager_type = Ogre::ST_GENERIC;
 mSceneMgr = mOgreRoot->createSceneManager( scene_manager_type );

 mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
 mMainLight = mSceneMgr->createLight("MainLight");
 mMainLight->setPosition(20,80,50);

 mCamera = mSceneMgr->createCamera( "OgreWidgetCam" );
 mCamera->setPosition(Ogre::Vector3(0,0,200));
 mCamera->lookAt(Ogre::Vector3(0,0,-300));
 mCamera->setNearClipDistance(1);
 
 mViewport = mOgreWindow->addViewport( mCamera );
 mViewport->setBackgroundColour(Ogre::ColourValue::Black);
 mCamera->setAspectRatio(Ogre::Real(mViewport->getActualWidth()) / Ogre::Real(mViewport->getActualHeight()));
}

.Load Scene

       Load an ogre head for this demo.
void OgreCoreRenderer::loadScene(){
 Ogre::Entity* ogreHead = mSceneMgr->createEntity("head", "ogrehead.mesh");
 mHeadNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
 mHeadNode->attachObject(ogreHead);
 mCamera->setAutoTracking(true, mHeadNode); 
}


.Release memory
void OgreWidget::release(){
 mOgreWindow->removeAllViewports();
 mOgreRoot->detachRenderTarget(mOgreWindow);
 mSceneMgr->clearScene();
 mOgreRoot->destroySceneManager(mSceneMgr);
 mOgreRoot->shutdown();
 delete mOgreRoot;
}


3.Using Ogre3D to update OgreWidget

.Make OgreWidget better performances

      Because we use Ogre3D to update(draw) window instead of Qt draw engine,we can do someting to make OgreWidget better performances.

.Disable auto fill background

      We can control auto fill background by setAutoFillBackground function, but notice this..


      Windows are always filled with QPalette::Window, unless the WA_OpaquePaintEvent or WA_NoSystemBackground attributes are set.

.Set Attributes in OgreWidget


      enum Qt::WidgetAttribute

  • WA_PaintOnScreen
            Draw on screen directly, notice that this flag is dependent on the platform it is used on. You may ignore it on Windows unless you want to reimplement paintEngine.
  •  WA_NoSystemBackground
            Indicates this widget has no background.
  • WA_OpaquePaintEvent
            You may enable it if there is flicker problem on your system, usually occurs on systems do not support double buffering.

.Overwrite event handle function
  • resizeEvent,
void OgreWidget::resizeEvent(QResizeEvent* evt){
 if(!mOgreWindow||!mCamera){
  return;
 } 
 mOgreWindow->windowMovedOrResized();
 mCamera->setAspectRatio(static_cast(width) / static_cast(height));
}
  • timerEvent
  • paintEvent
            Just Rendering with Ogre3D
void OgreWidget::render(){
 if(!mOgreRoot || !mOgreWindow){
  return;
 }
 mOgreRoot->_fireFrameStarted();
 mOgreWindow->update();
 mOgreRoot->_fireFrameRenderingQueued();
 mOgreRoot->_fireFrameEnded();
}
void OgreWidget::timerEvent(QTimerEvent* evt){
 render();
}
void OgreWidget::paintEvent(QPaintEvent* evt){
 render();
}

And don't forget to start timer.
OgreWidget::OgreWidget(QWidget *parent)
: QWidget(parent){
 ……
 startTimer(10);
}


4. Using OgreWidget

int main(int argc, char *argv[]){
 QApplication app(argc, argv);
 int appResult;

 OgreWidget *ogreSceneWidget=NULL;
 ogreSceneWidget = new OgreWidget();
 assert(ogreSceneWidget);
 ogreSceneWidget->loadScene();

 ogreSceneWidget->resize(800, 600);
 ogreSceneWidget->setWindowTitle("Integrating Ogre3D 1.7.4 with Qt 4.8.1...");

 ogreSceneWidget->show();
 appResult = app.exec();

 delete ogreSceneWidget;
 return appResult;
}

.Result




Referecnes:

(1).Ogre3D is a popular rendering engine for multiple platforms.
http://www.ogre3d.org/

(2).Qt is a cross-platform application framework for developing graphical user interface(GUI). Beside the framework for GUI, QT also has extensive module for usual development such like network、multimedia、database…
http://qt.nokia.com/

沒有留言:

張貼留言