本帖最后由 rcyboom 于 2011-10-16 16:29 编辑
/*记得在OSGChina中问过如何将osg渲染进普通qt窗口的问题,虽然照着别人的帮助依葫芦画瓢了一段代码可以运行,但是一直不知道为什么。这几天休假,正好想再学学OSG,于是下载了OSG3.01和QT4.7.4从源代码进行了编译。然后参考学习这个例子。(因为时隔这么久,网络上仍然找不到更详尽的osg嵌入qt的例子,同时不管在中文网还是英文网站,我搜索了一下,推荐的也只是这个例子)。为了方便分析和学习,我将函数拆散以调用顺序全部集成到构造函数中,原来所需的外部参数也放到构造函数中并带默认值。 使用方法: QOSGWidget可以当做普通QWidget使用,例如新建一个MainWindow工程,在MainWindow的构造函数中创建并且setCenterWidget即可。
代码分析: */
#include<QtCore/QTimer> #include<QtGui/QApplication>#include<QtGui/QGridLayout> #include<QObject> #include<osgViewer/CompositeViewer> #include<osgViewer/ViewerEventHandlers> #include<osgGA/TrackballManipulator> #include<osgDB/ReadFile> #include<osgQt/GraphicsWindowQt> #include<iostream>
class QOSGWidget:public QWidget,public osgViewer::CompositeViewer{ Q_OBJECT public: explicit QOSGWidget(osgViewer::ViewerBase::ThreadingModel threadingModel=osgViewer::CompositeViewer::SingleThreaded, QString WidgetTitle="",bool windowDecoration=false); virtual void paintEvent(QPaintEvent* event){frame();} /*由于继承于普通QWidget,需要使用osg的frame来自行绘制。*/ protected: QTimer _timer; QWidget* osgwidget; };
QOSGWidget::QOSGWidget(osgViewer::ViewerBase::ThreadingModel threadingModel,QString WidgetTitle,bool windowDecoration):QWidget():osgViewer::CompositeViewer()
{/*设置线程模型和创建图形设备相关参数*/
setThreadingModel(threadingModel);
osg::DisplaySettings* ds=osg::DisplaySettings::instance().get();
osg::ref_ptr<osg::GraphicsContext::Traits>traits=new osg::GraphicsContext::Traits;
traits->windowName=WidgetTitle.toStdString();
traits->windowDecoration=windowDecoration;
traits->x=this->x();
traits->y=this->y();
traits->width=this->width();
traits->height=this->height();
traits->doubleBuffer=true;
traits->alpha=ds->getMinimumNumAlphaBits();
traits->stencil=ds->getMinimumNumStencilBits();
traits->sampleBuffers=ds->getMultiSamples();
traits->samples=ds->getNumMultiSamples();
traits->supportsResize=true;
osg::ref_ptr<osg::Camera>camera=newosg::Camera;
/*关联camera对象的图形窗口到根据traits参数创建的GraphicsWindowQt窗口或者?这里的GraphicsWindowQt是新建的对象实例,应该作何理解呢?是图形渲染窗口呢还是OPenGL设备上下文?camera、GraphicsWindowQt以及view之间的关系怎么理解?*/
camera->setGraphicsContext(new osgQt::GraphicsWindowQt(traits.get()));
camera->setClearColor(osg::Vec4(0.2,0.2,0.6,1.0));
/*设置视口范围,这里设置为1/2窗口大小可以正常显示,可是如果我想在窗口的另外一半显示另外一个视角的渲染结果应该怎么做?是应该新增一个camera对象么?可如果新增另外一个camera的话,如何增加到下面的view中呢?*/
camera->setViewport(new osg::Viewport(0,0,traits->width,traits->height/2));
camera->setProjectionMatrixAsPerspective(30.0f,static_cast<double>(traits->width)/static_cast<double>(traits->height),1.0f,10000.0f);
osgViewer::View *view=new osgViewer::View;
view->setCamera(camera);
/*这里调用了CompositeViewer的addview,如果要实现上面的同一窗口不同视角的话是不是可以新增camera对象和view对象,然后再次调用addview呢?*/
addView(view);
osg::Node *scene=osgDB::readNodeFile("cow.osgt");
view->setSceneData(scene);
/*增加用户事件处理,可是如果注销这一句的话,仍然能用鼠标进行操作,为何?*/
view->addEventHandler(new osgViewer::StatsHandler);
/*设置导航方式,如果注销掉的话,显示的画面不堪入目啊。如果我不想使用导航,仅仅想要固定camera对象的话,是否可以使用类似view->getCamera()->setProjectionMatrix();或者直接使用camera->setProjectionMatrix();来设置呢?*/
view->setCameraManipulator(new osgGA::TrackballManipulator);
/*获取GraphicsWindowQt对象的指针,这里获取的指针对象是否就是上面根据traits参数创建的那一个?如果是的话,在上面保存指针的话/这里是不是就不用进一步转化了?*/
osgQt::GraphicsWindowQt *gw=dynamic_cast<osgQt::GraphicsWindowQt*>(camera->getGraphicsContext());
/*通过GraphicsWindowQt对象的getGLWidget方法获取GLWidget并加入到QOSGWidget的layout中去,看源码显示其为GraphicsWindowQt的友类,而GLWidget又从QGLWidget继承而来,那么是否可以这样认为QOSGWidget的父子关系呢:this->layout->GLWidget ?画面实际绘制在GLWidget 上?那GraphicsWindowQt在这里又处于哪一层,起什么作用呢?如果按照这种模式在qt中运行的话,鼠标消息是发给this呢还是直接由GLWidget 截获?*/
osgwidget=gw?gw->getGLWidget():NULL;
QVBoxLayout *layout=new QVBoxLayout(this);
layout->addWidget(osgwidget);
connect(&_timer,SIGNAL(timeout()),this,SLOT(update()));
_timer.start(10);
}
/*看完这简短的几句代码,不明白的东西有太多了,这还是在没深入OSG渲染流程的情况下。这一是我OSG实在是新手,二是实在看不懂GraphicsWindowQt的源代码,不明白他们的关系和作用分别是什么?而且可以将osg渲染嵌入到普通qt窗口中,同时也可以将qt窗口嵌入到osg场景中,不知道他们分别起什么作用?我编译的osg例子代码中只有osgviewQt可以正常运行,猜测中的那个将qt窗口嵌入osg场景中的osgQtWidgets并没有出现,自行编译也报好多错误,也看不到网络上的“重返德军总部”的效果。除了代码中的问题,我仔细想了下,还有如下几个问题:
1、将osg嵌入qt普通窗口的例子是osgviewQt,另外两个osgQtWidgets和osgQtBrowser是否是反向嵌入的例子?
2、一般将OSG嵌入QT的推荐方法是什么?能否给实现一个能在qt下当做普通qglwidget使用的类呢?这个例子虽然拼凑成功,但是很显然还有很多需要改进的地方,如更换场景root,操作camera等。
3、UI界面的window,viewer,camera,setGraphicsContext,CompositeViewer之间的关系如何,怎么理解?如果同一场景在同一窗口以不同的视角显示是怎么回事?同一场景在2个窗口以不同视角显示有时怎么回事?一个程序中不同rootnode的场景各自拥有单独的camera和view在不同的窗口显示又是怎么回事呢?问题多且杂乱无章,惭愧的首选是自己,但是这确实就是目前我所遇到的拦路狗,不期望哪位大侠能一一解释,不过就算回答一两个也十分感激不尽了。同时,我想大家试试看能否解我所惑,看看是不是很多新手都遇到了我这样不可理喻的问题呢?*/ |