解决方案一"/>
OSG嵌入Qt解决方案一
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 <iostream>
=================================================================
=================================================================
头文件包括完毕这后,我们开始思考,到底去继承什么样的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::AdapterWidget( QWidget * parent, const char * name, const QGLWidget * shareWidget, WindowFlags f):
{
}
void AdapterWidget::resizeGL( int width, int height )
{
}
void AdapterWidget::keyPressEvent( QKeyEvent* event )
{
}
void AdapterWidget::keyReleaseEvent( QKeyEvent* event )
{
}
void AdapterWidget::mousePressEvent( QMouseEvent* event )
{
}
void AdapterWidget::mouseReleaseEvent( QMouseEvent* event )
{
}
void AdapterWidget::mouseMoveEvent( QMouseEvent* event )
{
}
根据我的了解,实际上,上面的那个窗口仅仅实现了一帧里面的viewerInit。其他的任何事情都没做。于是乎需要做realize吧~如果不知道OSG一帧大概需要做些什么东西的人,可以看我的某一篇日志,里面介绍了一帧里面OSG所做的五个大动作。而realize实际上只是属于第一个动作里面收尾的一个动作(也就是初始化视景器)。
还是让我们来看看初始化视景器的代码吧~
lass ViewerQT : public osgViewer::Viewer, public AdapterWidget
{
};
既然场景已经初始化完毕了,这样简单的一帧就算是完成了。(实际上一帧中的五个大动作中,后面四个都采用的默认设置,那么这里也可以顺便总结一下,OSG一帧五个大动作中,第一帧实际上是准备整个场景,其中包含了第一次运行应用程序对OSG环境的初始化,而恰好,我们在做OSG嵌入其他GUI时做的就是这个初始化工作,因为默认的初始化工作满足不了我们的需求,所以我们需要自己去写。)
然后调用main函数,看看结果吧~
int main( int argc, char *argv[])
{
}
这里需要注意的是Qt是一个非常懒的家伙~你必须告诉它去刷新,它才肯动一下,所以那个设置QTimer的地方在所有需要有定时刷新机制的程序中必须用到。
更多推荐
OSG嵌入Qt解决方案一
发布评论