天天看点

Ogre3D嵌入Qt框架

 http://www.cppblog.com/yuanyajie/archive/2007/05/21/24528.aspx

按照经典的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;

}

继续阅读