​OSG与Qt结合介绍

http://blog.sina.com.cn/s/blog_d01f29a10101m8fg.html
​OSG与Qt结合,国内网站上的资料非常少,最有助于理解OSG的资料我可以推荐一下:王锐老师的《最长的一帧》
要想驾驭一个SDK,首先就得了解其工作原理。王老师那本电子书里面就介绍了一帧的画面,OSG所做的全部内容,几乎可以这么说:你如果弄明白了一帧中OSG所做的东西,你就几乎掌握了OSG的全部,因为OSG本来就是个图形渲染引擎,学好OSG,只需要搞清楚它一帧做的事情就足够了。
这里我来记录一个嵌入Qt的OSG渲染窗口是怎么做到的,首先你要相信,这很简单,因为看完这篇文章,你一定可以模仿或者做出更好的(直接拷贝所有代码进你的main.cpp也行~)。没错,这里我用到的例子就是OSG的example里面的。
此处需要申明的是,我的Qt的版本是4.6.2,如果是其他版本的话,这个程序很明显不一定能成功运行~
下面是需要包含的头文件:(有点乱,有几个好像是不需要的,因为写重复了)
#include <QtGui/QApplication>
#include <osg/ArgumentParser>
#include <osgViewer/Viewer>
#include <osgViewer/CompositeViewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
#include <osgDB/ReadFile>
#include <QtCore/QString>
#include <QtCore/QTimer>
#include <QtGui/QKeyEvent>
#include <QtGui/QApplication>
#include <QtOpenGL/QGLWidget>
#include <QtGui/QMainWindow>
#include <QtGui/QMdiSubWindow>
#include <QtGui/QMdiArea>
#include<qtgui/qtgui>
using Qt::WindowFlags;
#include

=================================================================
头文件包括完毕这后,我们开始思考,到底去继承什么样的Qt窗口来容纳OSG呢?首先,学过windowsSDK编程的人都知道,MFC是一个死的,会windowsSDK编程的都不会在做东西的时候首先考虑MFC。然后这里我要说的是Qt实际上就仅仅是一个漂亮点的MFC,或许它的信号机制在反应速度上不如MFC,但是它从外观和安全和可移植性都比MFC好。而且,我要说明的是,Qt看起来仅仅是MFC里面的基于对话框的编程,乍一看是挺恶心的,那么死板的对话框,所有的创意都不可能实现了。(但是那只是乍一看~~);
对程序员帮助最大的东西莫过于一个帮助手册,阅读Qt的帮助手册,发现,其实这种开源的东西是需要靠自己去继承它并发展新的东西的。扯远了~~
我们的目的是在Qt的窗口上嵌套OSG,最简单的方法其实就是用多进程,以一种外部控制的方式使两个窗口看起来像是父子关系,但是不是真正意义上的父子关系。于是这种方案抛弃了。
接着分析,要潜入一个Qt类型的主窗口,就必须是Qt类型的窗口。于是就需要从众多Q系列的窗口里需要找到一个支撑OSG画面的窗口类型。OSG是基于OpenGL的渲染引擎吧而恰好,Qt也有对OpenGL窗口支持的Q类型窗口,这个窗口类型的名字就是QGLWidget,于是乎,基于这个类派生自己的OSG窗口似乎是个不错的想法(嗯确实是个不错的想法)。
QGLWidget是多继承了QWidget(使这种窗口具有了Q系列的血统)和QGL(又让此窗口有了三维视觉效果),是个不错的想法。于是,下面就是最原始的嵌入式OSG的窗口类别~,以及实现方法。
class AdapterWidget : public QGLWidget
{
public:
AdapterWidget( QWidget * parent = 0, const char * name = 0, const QGLWidget * shareWidget = 0, WindowFlags f = 0 );
virtual ~AdapterWidget()
{
}
osgViewer::GraphicsWindow* getGraphicsWindow() { return _gw.get(); }
const osgViewer::GraphicsWindow* getGraphicsWindow() const { return _gw.get(); }
protected:
void init();
virtual void resizeGL( int width, int height );
virtual void keyPressEvent( QKeyEvent* event );
virtual void keyReleaseEvent( QKeyEvent* event );
virtual void mousePressEvent( QMouseEvent* event );
virtual void mouseReleaseEvent( QMouseEvent* event );
virtual void mouseMoveEvent( QMouseEvent* event );
osg::ref_ptrosgViewer::GraphicsWindowEmbedded _gw;
};
AdapterWidget::AdapterWidget( QWidget * parent, const char * name, const QGLWidget * shareWidget, WindowFlags f):
QGLWidget(parent, shareWidget, f)
{
_gw = new osgViewer::GraphicsWindowEmbedded(0,0,width(),height());
setFocusPolicy(Qt::ClickFocus);
}
void AdapterWidget::resizeGL( int width, int height )
{
_gw->getEventQueue()->windowResize(0, 0, width, height );
_gw->resized(0,0,width,height);
}
void AdapterWidget::keyPressEvent( QKeyEvent* event )
{
_gw->getEventQueue()->keyPress( (osgGA::GUIEventAdapter::KeySymbol) (event->text().toAscii().data() ) );
}
void AdapterWidget::keyReleaseEvent( QKeyEvent
event )
{
_gw->getEventQueue()->keyRelease( (osgGA::GUIEventAdapter::KeySymbol) (event->text().toAscii().data() ) );
}
void AdapterWidget::mousePressEvent( QMouseEvent
event )
{
int button = 0;
switch(event->button())
{
case(Qt::LeftButton): button = 1; break;
case(Qt::MidButton): button = 2; break;
case(Qt::RightButton): button = 3; break;
case(Qt::NoButton): button = 0; break;
default: button = 0; break;
}
_gw->getEventQueue()->mouseButtonPress(event->x(), event->y(), button);
}
void AdapterWidget::mouseReleaseEvent( QMouseEvent* event )
{
int button = 0;
switch(event->button())
{
case(Qt::LeftButton): button = 1; break;
case(Qt::MidButton): button = 2; break;
case(Qt::RightButton): button = 3; break;
case(Qt::NoButton): button = 0; break;
default: button = 0; break;
}
_gw->getEventQueue()->mouseButtonRelease(event->x(), event->y(), button);
}
void AdapterWidget::mouseMoveEvent( QMouseEvent* event )
{
_gw->getEventQueue()->mouseMotion(event->x(), event->y());
}
根据我的了解,实际上,上面的那个窗口仅仅实现了一帧里面的viewerInit。其他的任何事情都没做。于是乎需要做realize吧~如果不知道OSG一帧大概需要做些什么东西的人,可以看我的某一篇日志,里面介绍了一帧里面OSG所做的五个大动作。而realize实际上只是属于第一个动作里面收尾的一个动作(也就是初始化视景器)。
还是让我们来看看初始化视景器的代码吧~
lass ViewerQT : public osgViewer::Viewer, public AdapterWidget
{
public:
ViewerQT(QWidget * parent = 0, const char * name = 0, const QGLWidget * shareWidget = 0, WindowFlags f = 0):
AdapterWidget( parent, name, shareWidget, f )
{
getCamera()->setViewport(new osg::Viewport(0,0,width(),height()));
getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(width())/static_cast(height()), 1.0f, 10000.0f);
getCamera()->setGraphicsContext(getGraphicsWindow());
setThreadingModel(osgViewer::Viewer::SingleThreaded);
connect(&_timer, SIGNAL(timeout()), this, SLOT(updateGL()));
_timer.start(10);
}
virtual void paintGL()
{
frame();
}

protected:
    QTimer _timer;

};
既然场景已经初始化完毕了,这样简单的一帧就算是完成了。(实际上一帧中的五个大动作中,后面四个都采用的默认设置,那么这里也可以顺便总结一下,OSG一帧五个大动作中,第一帧实际上是准备整个场景,其中包含了第一次运行应用程序对OSG环境的初始化,而恰好,我们在做OSG嵌入其他GUI时做的就是这个初始化工作,因为默认的初始化工作满足不了我们的需求,所以我们需要自己去写。)
然后调用main函数,看看结果吧~
int main( int argc, char argv[])
{
QApplication a( argc, argv );
osg::ref_ptrosg::Node loadedModel = osgDB::readNodeFile(“osgcool.osg”);
std::cout<<“Using ViewetQT MDI version”<<std::endl;
ViewerQT
viewerWindow = new ViewerQT;
viewerWindow->setCameraManipulator(new osgGA::TrackballManipulator);
viewerWindow->setSceneData(loadedModel.get());
QMainWindow* mw = new QMainWindow();
QMdiArea* mdiArea = new QMdiArea(mw);
mw->setCentralWidget(mdiArea);
QMdiSubWindow *subWindow = mdiArea->addSubWindow(viewerWindow);
subWindow->showMaximized();
subWindow->setWindowTitle(“New Window”);
mw->show();
a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) );
return a.exec();
}
这里需要注意的是Qt是一个非常懒的家伙~你必须告诉它去刷新,它才肯动一下,所以那个设置QTimer的地方在所有需要有定时刷新机制的程序中必须用到。
斜体样式

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值