一、概述
OpenSceneGraph(简称OSG)使用OpenGL技术开发,是一套基于C++平台的应用程序接口(API),它让程序员能够更加快速、便捷地创建高性能、跨平台的交互式图形程序。它作为中间件(middleware)为应用软件提供了各种高级渲染特性,IO,以及空间结构组织函数;而更低层次的OpenGL 硬件抽象层(HAL)实现了底层硬件显示的驱动。
网上关于编译osg的资料太多,关于OSG的编译在此不过多赘述,本人使用的是vs2015+osg365,本篇将详细讲解一下如何在QT中搭建OSG开发环境。
无论是集成到QT还是MFC还是其他开发环境,归根到底是显示方式的不同,就好比看视频,可以投屏、可以投影,只要找到显示的窗体类,借助窗体类完成显示即可,这是问题的思路。
OSG集成到QT中有两种方式:
- osgQt。在较老版本的osg中自带osgQt源码包,主要适配的是QT4,网址:osgQt
- osgQOpenGL。需要自行编译适配的osg版本,主要适配QT5。
本文采用的是第一种方式,采用osgQt的方式,源码集成。为什么采用源码集成而不采用原有的lib文件,是因为方便做二次开发,这在后面用到会逐渐讲到。
二、准备 GraphicsWindowQt
首先是文件GraphicsWindowQt源码,这里拿到源码需要修改一下,修改项目如下:
- GraphicsWindowQt.h:
- #include <QMutex>改为#include <QtCore/QMutex>;
- 删除 #include <osgQt/Export>;
- 删除 OSGQT_EXPORT 关键字。
- GraphicsWindowQt.cpp:
- #include <QMutex>改为#include <QtCore/QMutex>;
- 删除 OSGQT_EXPORT 关键字;
- 578行:
getEventQueue()->syncWindowRectangleWithGraphicsContext();
改为:
getEventQueue()->getCurrentEventState()->getGraphicsContext();
如果不想改,我改好的地址:osgQt修改版,提取码:0501。
三、代码集成
- 新建空白Qt Widgets Application 项目,新建osgwidget QT设计师类,pro文件中引入opengl:
QT += core gui opengl
- 引入osg相关外部依赖:
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../osg/denpendency/osg/lib/ -losg else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../osg/denpendency/osg/lib/ -losgd else:unix: LIBS += -L$$PWD/../../osg/denpendency/osg/lib/ -losg INCLUDEPATH += $$PWD/../../osg/denpendency/osg/include DEPENDPATH += $$PWD/../../osg/denpendency/osg/include win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../osg/denpendency/osg/lib/ -lOpenThreads else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../osg/denpendency/osg/lib/ -lOpenThreadsd else:unix: LIBS += -L$$PWD/../../osg/denpendency/osg/lib/ -lOpenThreads INCLUDEPATH += $$PWD/../../osg/denpendency/osg/include DEPENDPATH += $$PWD/../../osg/denpendency/osg/include win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../osg/denpendency/osg/lib/ -losgGA else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../osg/denpendency/osg/lib/ -losgGAd else:unix: LIBS += -L$$PWD/../../osg/denpendency/osg/lib/ -losgGA INCLUDEPATH += $$PWD/../../osg/denpendency/osg/include DEPENDPATH += $$PWD/../../osg/denpendency/osg/include win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../osg/denpendency/osg/lib/ -losgViewer else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../osg/denpendency/osg/lib/ -losgViewerd else:unix: LIBS += -L$$PWD/../../osg/denpendency/osg/lib/ -losgViewer INCLUDEPATH += $$PWD/../../osg/denpendency/osg/include DEPENDPATH += $$PWD/../../osg/denpendency/osg/include win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../osg/denpendency/osg/lib/ -losgDB else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../osg/denpendency/osg/lib/ -losgDBd else:unix: LIBS += -L$$PWD/../../osg/denpendency/osg/lib/ -losgDB INCLUDEPATH += $$PWD/../../osg/denpendency/osg/include DEPENDPATH += $$PWD/../../osg/denpendency/osg/include
这里文件路径替换成你自己的osg文件路径。
-
main.h:
#include "osgwidget.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); OSGWidget w; w.show(); return a.exec(); }
- osgwidget.h:
#ifndef OSGWIDGET_H #define OSGWIDGET_H #include <QWidget> #include <QTimer> #include <osgDB/ReadFile> #include <osg/Group> #include <osg/Node> #include <osg/Camera> #include <osgGA/TrackballManipulator> #include <osgGA/StateSetManipulator> #include <osgViewer/ViewerEventHandlers> #include "GraphicsWindowQt.h" // 这个是本地自己建的。所以用双引号 #include <QDebug> namespace Ui { class OSGWidget; } class OSGWidget : public QWidget { Q_OBJECT public: explicit OSGWidget(QWidget *parent = nullptr); ~OSGWidget(); private: Ui::OSGWidget *ui; public: QTimer* m_timer; osgViewer::Viewer* viewer; public: void initEarth(); public slots: void updateFrame(); }; #endif // OSGWIDGET_H
- osgwidget.cpp:
#include "osgwidget.h" #include "ui_osgwidget.h" OSGWidget::OSGWidget(QWidget *parent) : QWidget(parent), ui(new Ui::OSGWidget) { ui->setupUi(this); m_timer = new QTimer; viewer = new osgViewer::Viewer; initEarth(); } OSGWidget::~OSGWidget() { delete ui; // delete m_timer; } void OSGWidget::initEarth(){ // 设置模型 osg::ref_ptr<osg::Group> root = new osg::Group; // 显示cow.osg 模型 root->addChild(osgDB::readNodeFile("cow.osg")); // 显示 .earth 文件中的地球模型 // root->addChild(osgDB::readNodeFile("china-simple-3d.earth")); osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits; traits->windowDecoration = false;//声明是否显示窗口的描述 traits->x = 50; traits->y = 50; traits->width = 800; traits->height = 600; traits->doubleBuffer = true;//创建图形窗口是否使用双缓存 osg::ref_ptr<osg::Camera> camera = new osg::Camera; camera->setGraphicsContext(new osgQt::GraphicsWindowQt(traits.get())); camera->setClearColor(osg::Vec4(0.2f, 0.2f, 0.6f, 1.0)); camera->setViewport(new osg::Viewport(0, 0, 800, 600)); camera->setProjectionMatrixAsPerspective(30.0, 800.0/600.0, 1.0, 10000.0); //设置渲染器 viewer->setCamera(camera); viewer->setSceneData(root); viewer->setCameraManipulator(new osgGA::TrackballManipulator); viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);//创建为单线程 viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet())); viewer->addEventHandler(new osgViewer::WindowSizeHandler); viewer->addEventHandler(new osgViewer::StatsHandler); osgQt::GraphicsWindowQt* gw = dynamic_cast<osgQt::GraphicsWindowQt*>(camera->getGraphicsContext()); // 这里是直接在ui文件中添加了一个布局,重命名成了horizontalLayoutOSG ui->horizontalLayoutOSG->addWidget((QWidget*)(gw->getGLWidget())); QObject::connect(m_timer, SIGNAL(timeout()), this, SLOT(updateFrame())); m_timer->start(5); // 每5ms触发一次帧的刷新 } void OSGWidget::updateFrame(){ viewer->frame(); }
- 将之前修改好的GraphicsWindowQt.h,GraphicsWindowQt.cpp文件引入到项目中即可,如图: