1、首先要在vs2010中创建一个基于qt的QWidge工程(OsgQtTest),然后对osgqtest.h进行修改,如下代码:
#ifndef OSGQTTEST_H
#define OSGQTTEST_H
#include <osgLib.h>
#include <QtCore/QTimer>
#include <QtWidgets/QApplication>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>
#include <osgViewer/CompositeViewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
#include <osgDB/ReadFile>
#include <osgQt/GraphicsWindowQt>
#include <iostream>
//CompositeViewer是多视景器
//Viewer是单视景器
class OsgQtTest : public QWidget,public osgViewer::CompositeViewer
{
Q_OBJECT
public:
OsgQtTest(osgViewer::ViewerBase::ThreadingModel threadingModel=osgViewer::CompositeViewer::SingleThreaded);
~OsgQtTest();
QWidget* addViewWidget( osgQt::GraphicsWindowQt* gw, osg::Node* scene );
osgQt::GraphicsWindowQt* createGraphicsWindow( int x, int y, int w, int h, const std::string& name="", bool windowDecoration=false );
virtual void paintEvent( QPaintEvent* event );
protected:
QTimer _timer;
};
#endif // OSGQTTEST_H
2、osgqttest.cpp代码:
#include "osgqttest.h"
OsgQtTest::OsgQtTest(osgViewer::ViewerBase::ThreadingModel threadingModel): QWidget()
{
/*设置线程模式,线程模式包括:
SingleThreaded表示单线程模式,OSG 不会创建任何新线程来完成场景的筛选和渲染,因而也不会对渲染效率的提高有任何助益。它适合任何配置下使用。
CullDrawThreadPerContext:OSG 将为每一个图形设备上下文(GraphicsContext)创建一个图形线程,以实现并行的渲染工作。如果有多个CPU 的话,
那么系统将尝试把线程分别放在不同的CPU 上运行,不过每一帧结束前都会强制同步所有的线程。
ThreadPerContext
DrawThreadPerContext:这一线程模型同样会为每个GraphicsContext 创建线程,并分配到不同的CPU 上。十分值得注意的是,这种模式会在当前帧的所有
线程完成工作之前,开始下一帧。
CullThreadPerCameraDrawThreadPerContext:这一线程模型将为每个GraphicsContext和每个摄像机创建线程,这种模式同样不会等待前一次的渲染结束,
而是返回仿真循环并再次开始执行frame 函数。如果您使用四核甚至更高的系统配置,那么使用这一线程模型将最大限度地发挥多CPU 的处理能力。
ThreadPerCamera
AutomaticSelection
*/
setThreadingModel(threadingModel);
// disable the default setting of viewer.done() by pressing Escape.
setKeyEventSetsDone(0);//来设置自定义的退出键(缺省是GUIEventAdapter::KEY_Escape)。
//在坐标(0,0)处创建一个窗口,并将cow.osgt设置到该窗口中
QWidget* widget1 = addViewWidget( createGraphicsWindow(0,0,100,100), osgDB::readNodeFile("cow.osgt") );
QWidget* widget2 = addViewWidget( createGraphicsWindow(0,0,100,100), osgDB::readNodeFile("glider.osgt") );
QWidget* widget3 = addViewWidget( createGraphicsWindow(0,0,100,100), osgDB::readNodeFile("axes.osgt") );
QWidget* widget4 = addViewWidget( createGraphicsWindow(0,0,100,100), osgDB::readNodeFile("fountain.osgt") );
//在坐标(900,100)处创建一个窗口,并将dumptruck.osgt设置到该窗口中
QWidget* popupWidget = addViewWidget( createGraphicsWindow(900,100,320,240,"Popup window",true), osgDB::readNodeFile("dumptruck.osgt") );
//以非模态窗口显示,此窗口是与主窗口分割开的
popupWidget->show();
QGridLayout* grid = new QGridLayout;//创建一个网络布局
grid->addWidget( widget1, 0, 0 );//在第0行,0列添加一个窗口
grid->addWidget( widget2, 0, 1 );//在第0行,1列添加一个窗口
grid->addWidget( widget3, 1, 0 );//在第1行,0列添加一个窗口
grid->addWidget( widget4, 1, 1 );//在第1行,1列添加一个窗口
setLayout( grid );//将该布局设置到主窗口中
connect( &_timer, SIGNAL(timeout()), this, SLOT(update()) );
_timer.start( 10 );
}
OsgQtTest::~OsgQtTest()
{
}
QWidget* OsgQtTest::addViewWidget( osgQt::GraphicsWindowQt* gw, osg::Node* scene )
{
osgViewer::View* view = new osgViewer::View;//创建一个渲染器
addView( view );//将渲染器加入到窗口中去
osg::Camera* camera = view->getCamera();//获得渲染器中的相机
//视景器Viewer 的主/从摄像机均需要使用setGraphicsContext设置对应的图形设备上下文,实际上也就是对应的显示窗口,那么gw就是要显示的窗口
camera->setGraphicsContext( gw );
const osg::GraphicsContext::Traits* traits = gw->getTraits();//可通过窗口的getTraits获得窗口的属性
camera->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) );//设置清除缓存区背景的颜色。RGBA格式。
camera->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) );//设置视口的尺寸与位置。
//以透视投影的方式来设置投影矩阵。30为透视投影中的视角,第二个参数一般都是窗口的宽/高,第三个参数投影钟的近视角,第四个参数为投影钟的远视角
camera->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(traits->width)/static_cast<double>(traits->height), 1.0f, 10000.0f );
view->setSceneData( scene );//将模型添加到渲染器中
view->addEventHandler( new osgViewer::StatsHandler );//添加一些常用状态设置
view->setCameraManipulator( new osgGA::TrackballManipulator );//设置一个操作器
return gw->getGLWidget();//获得窗口对象,相当于QWidget*,可通过此对象对界面进行设置以及添加到当前的window中
}
osgQt::GraphicsWindowQt* OsgQtTest::createGraphicsWindow( int x, int y, int w, int h, const std::string& name, bool windowDecoration)
{
osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
//声明一个嵌入窗口的变量,只要是有多个窗口必须使用此对象进行设置
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
traits->windowName = name;//设置窗口的标题
traits->windowDecoration = windowDecoration;//是否显示窗口的描述,默认为false不显示
traits->x = x;//设置窗口显示的x坐标
traits->y = y;//设置窗口显示的y坐标
traits->width = w;//设置窗口的宽度
traits->height = h;//设置窗口的高度
traits->doubleBuffer = true;//创建新的图形窗口是否使用双缓冲特性
traits->alpha = ds->getMinimumNumAlphaBits();//获得最小透明值
traits->stencil = ds->getMinimumNumStencilBits();//获得模板缓存的最小位数
traits->sampleBuffers = ds->getMultiSamples();
traits->samples = ds->getNumMultiSamples();
return new osgQt::GraphicsWindowQt(traits.get());//通过以上的设置参数来创建一个qt的窗口对象
}
void OsgQtTest::paintEvent( QPaintEvent* event )
{
/*
frame()函数的源代码如下:
void ViewerBase::frame(double simulationTime)
{
if (_done) return;
// OSG_NOTICE<<std::endl<<"CompositeViewer::frame()"<<std::endl<<std::endl;
if (_firstFrame)
{
viewerInit();//如果这是仿真系统启动后的第一帧,则执行viewerInit()
if (!isRealized())//viewerInit();此时如果还没有执行realize()函数,则执行它。
{
realize();
}
_firstFrame = false;
}
advance(simulationTime);//执行advance 函数
//执行eventTraversal 函数,顾名思义,这个函数将负责处理系统产生的各种事件,诸
//如鼠标的移动,点击,键盘的响应,窗口的关闭等等,以及摄像机与场景图形的事件回调
//(EventCallback)。
eventTraversal();
//执行updateTraversal 函数,这个函数负责遍历所有的更新回调(UpdateCallback);
//除此之外,它的另一个重要任务就是负责更新DatabasePager 与ImagePager 这两个重要的分
//页数据处理组件。
updateTraversal();
//执行renderingTraversals 函数,这里将使用较为复杂的线程处理方法,完成场景的筛选(cull)和绘制(draw)工作。
renderingTraversals();
}
*/
frame();//实时对其进行渲染
}
3、main.cpp代码:
#include "osgqttest.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
OsgQtTest* viewWidget = new OsgQtTest();
viewWidget->setGeometry( 100, 100, 640, 480 );
viewWidget->show();
return a.exec();
}
最终效果图如下: