前记
一般osg在vs2019编译器运行,只要配置相应的环境就能正常运行,但是如果要在qt中运行需要自己手动配置类才能正常运行,以下是qt中运行osg的一个示例
1、创建QT项目
首先正常创建QT项目(这里用的是MSVC2019),然后进入mainwindow.ui界面设计页面,将OpenGlWidaet拖入页面:
2、配置OSG环境
请现在自己的电脑配置好osg的环境,并控制台确定osg可用,然后在.pro文件中引入os9,加入如下内容:
FORMS += mainwindow.ui
INCLUDEPATH += $${ROOT}\include
LIBS += $${ROOT}\lib\OpenThreadsd.lib
LIBS += $${ROOT}\lib\osgd.lib
LIBS += $${ROOT}\lib\osgDBd.lib
LIBS += $${ROOT}\lib\osgGAd.lib
LIBS += $${ROOT}\lib\osgQt5d.lib
LIBS += $${ROOT}\lib\osgTextd.lib
LIBS += $${ROOT}\lib\osgUtild.lib
LIBS += $${ROOT}\lib\osgViewerd.lib
QT += opengl
注意:ROOT = D:\SWEnvironment\OSG为自己电脑OSG所在位置,这个路径一定要对应上。
3、创建OSG类
也可以说是这个openGLWidget窗口的类,要想在这个窗口显示内容,需要为其创建一个单独的类,然后将这个窗口提升为这个类,即可,步骤如下:
1)创建openGLWidget类(名称可以自己随意设置,这里设置为openGLWidget)
然后一直下一步,直到创建完成;
2)创建完成后,设置"openglwidget.h"和"openglwidget.cpp"的内容
(1)openglwidget.h
#ifndef OSGVIEW_H
#define OSGVIEW_H
#include <osgViewer/Viewer>
#include <osgViewer/CompositeViewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
#include <osgDB/ReadFile>
#include <QString>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QOpenGLWidget>
#include <QMainWindow>
#include <iostream>
class AdapterWidget : public QOpenGLWidget//QOpenGLWidget类是用于呈现OpenGL图形的小部件
{
public:
AdapterWidget(QWidget *parent = 0, const char* name = 0, const QOpenGLWidget* shareWidget = 0,Qt::WindowFlags f = Qt::Widget);
virtual ~AdapterWidget(){}
osgViewer::GraphicsWindow* getGraphicsWindow()//应该是用于输出图像的
{
return mGw.get();
}
const osgViewer::GraphicsWindow* getGraphicsWidow()const//应该是多余的,没有调用到
{
return mGw.get();
}
protected:
virtual void resizeGL(int width, int height);//设置OpenGL视区、投影等,每当部件调整大小时,将会被调用
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);//鼠标移动事件
virtual void wheelEvent(QWheelEvent* event);//滚轮事件
//osg图形设备
osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> mGw;//GraphicsWindowEmbedded提供了用于操作窗口设备的方法,同时拥有了处理事件的能力,当有事件发生时,可接收事件进行响应处理
};
class OpenGLWidget : public osgViewer::Viewer, public AdapterWidget
{
public:
OpenGLWidget(QWidget * parent = 0, const char *name = 0, const QOpenGLWidget * shareWidget = 0, Qt::WindowFlags f = Qt::Widget);
~OpenGLWidget(){}
virtual void paintGL();//渲染OpenGL场景,需要更新Widget时就会调用
protected:
osg::Timer mTimer;//定义一个定时器,用来计算读取一个模型的时间(就是本项目运行后在控制台输出的那个时间)
double mStrTime;
double mEndTime;
double mSleepTime;
int num;
};
#endif // OSGVIEW_H
(2)openglwidget.cpp
#include "openglwidget.h"
#include <QDebug>
AdapterWidget::AdapterWidget(QWidget *parent, const char *name, const QOpenGLWidget *shareWidget, Qt::WindowFlags f)
{
mGw = new osgViewer::GraphicsWindowEmbedded(this->x(), this->y(), width(), height());
setFocusPolicy(Qt::ClickFocus);
}
//设置OpenGL视口,投影等。每当调整Widget的大小时(第一次显示窗口Widget时会调用它,因为所有新创建Widget都会自动获得调整大小的事件)
void AdapterWidget::resizeGL(int width, int height)
{
mGw->getEventQueue()->windowResize(0, 0, width, height);
mGw->resized(0, 0, width, height);
}
void AdapterWidget::keyPressEvent(QKeyEvent *event)
{
mGw->getEventQueue()->keyPress((osgGA::GUIEventAdapter::KeySymbol) *(event->text().toUtf8().data()));
}
void AdapterWidget::keyReleaseEvent(QKeyEvent *event)
{
mGw->getEventQueue()->keyRelease((osgGA::GUIEventAdapter::KeySymbol) *(event->text().toUtf8().data()));
}
void AdapterWidget::mousePressEvent(QMouseEvent *event)
{
int button = 0;
switch (event->button()) {
case (Qt::LeftButton):
button = 1;
break;
case (Qt::MiddleButton):
button = 2;
break;
case (Qt::RightButton):
button = 3;
break;
case (Qt::NoButton):
button = 4;
break;
default:
button = 0;
break;
}
mGw->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::MiddleButton):
button = 2;
break;
case (Qt::RightButton):
button = 3;
break;
case (Qt::NoButton):
button = 4;
break;
default:
button = 0;
break;
}
mGw->getEventQueue()->mouseButtonRelease(event->x(), event->y(), button);
}
void AdapterWidget::mouseMoveEvent(QMouseEvent *event)
{
mGw->getEventQueue()->mouseMotion(event->x(), event->y());
}
void AdapterWidget::wheelEvent(QWheelEvent *event)
{
mGw->getEventQueue()->mouseScroll(event->angleDelta().y() > 0 ? osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN);
}
OpenGLWidget::OpenGLWidget(QWidget *parent, const char *name, const QOpenGLWidget *shareWidget, Qt::WindowFlags f) : AdapterWidget(parent, name, shareWidget, f)
{
this->setMouseTracking(true);
getCamera()->setViewport(new osg::Viewport(0, 0, width(), height()));
getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(width()) / static_cast<double>(height()), 1.0f, 10000.0f);
getCamera()->setGraphicsContext(getGraphicsWindow());
setThreadingModel(osgViewer::Viewer::SingleThreaded);
mStrTime = 0.0;
mEndTime = 0.0;
mSleepTime = 0.0;
num = 0;
}
//渲染OpenGL场景,需要更新Widget时就会调用
void OpenGLWidget::paintGL()
{
mStrTime = mTimer.tick();
frame();
num++;
mEndTime = mTimer.tick();
//计算睡眠所需时间
mSleepTime = 1.0 / 60.0 - mTimer.delta_s(mStrTime, mEndTime);
if(mSleepTime < 0){
mSleepTime = 0.0;
}
//睡眠
OpenThreads::Thread::microSleep(mSleepTime * 1000000); //微秒
Sleep(mSleepTime * 1000); //毫秒
double mTime = mTimer.tick();
//递归调用
update();
}
3)OpenGLWidget窗口组件提升类
上面的类是定义一些基本操作,这样才能使OpenGLWidget这个窗口可用,类创建完成后,设置窗口,如下:
4、初始化mainwindow
在一切就绪后,需要在主窗口初始化一下,这样才能让可视化的内容在OpenGLWidget窗口显示
1)在mainwindow.h中添加两个变量,如下
osg::ref_ptr<osg::Group> group;
osg::ref_ptr<osg::Geometry> geometry;//几何体对象,
注意:记得引入osg相关头文件包
2)mainwindow.cpp初始化
将主窗口与OpenGLWidget窗口双向绑定,在构造方法中加入一下内容:
QMainWindow * mw = new QMainWindow(this);
mw->setWindowFlags(Qt::Widget);//设置窗口属性,如果继承QDialog,那窗口就只有关闭按钮,如果继承QWidget,那么就有关闭,最大化,最小化三个按钮
geometry = NULL;
group = new osg::Group;
osg::StateSet *set = group->getOrCreateStateSet();
set->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
set->setAttributeAndModes(new osg::PolygonOffset(1.0f,1.0f),osg::StateAttribute::ON);
osgGA::TrackballManipulator *t;
t = new osgGA::TrackballManipulator();
t->setAllowThrow(false);//禁止持续动
ui->openGLWidget = new OpenGLWidget(mw);
ui->openGLWidget->setCameraManipulator(t);
ui->openGLWidget->addEventHandler(new osgViewer::WindowSizeHandler);
ui->openGLWidget->addEventHandler(new osgViewer::StatsHandler);
ui->openGLWidget->setSceneData(group);
mw->setCentralWidget(ui->openGLWidget);
this->setCentralWidget(mw);
如下图:
这样大功告成了,只需要往group中添加节点就行,就可以正常显示了
5、测试
简单创建一个按钮进行测试,创建后转到槽
槽函数编写内容:加入一个飞机模型,然后运行
结果:
大功告成,可以正常按osg的思路编写代码了,如果需要更改键盘鼠标事件,可以再OpenGLWidget类中修改即可。