OSG嵌入Qt的第二种方式:使用QOpenGLWidget/QGLWidget

几天前有朋友问OSG嵌入Qt的思路。我说整体思路就是用OpenGL的方式来进行OSG的绘制,而正好Qt已经整合了OpenGL的功能,我们可以以此为依托来进行OSG的渲染绘制工作。而在Qt中却有QWidget和QGraphicsView两种不同的体系框架,于是我们也就有了两种不同的嵌入方式,关于QGraphicsView的嵌入方式我前面的博客OSGEarth嵌入Qt的QGraphicsView框架已经完成了,本篇是增加对QWidget体系的讲解。

Qt中具有OpenGL功能的是一个继承自QWidget的widget,叫做QGLWidget,但是在Qt5.5的版本中此类已被废弃,取而代之的是一个叫做QOpenGLWidget的类。在此,我用的是5.5版本的QOpenGLWidget,若是您用的之前的Qt版本请使用QGLWidget。
首先,我们需要处理一下按键、鼠标事件,处理的方式与QGraphicsView体系中使用的方式是相同的,代码也没太大变化,可参看OSGEarth嵌入Qt的QGraphicsView框架变化的地方在于继承的对象变了,在QGraphicsView体系中EventAdapter 继承自QGraphicsView,现在我们需要EventAdapter 继承自QOpenGLWidget。
完成事件处理后,我们来进行OSG的嵌入工作。
首先是头文件:

class Widget3D : public EventAdapter, public osgViewer::Viewer
{
    Q_OBJECT

public:
    Widget3D(QWidget *parent = 0);
    ~Widget3D();

    osgViewer::Viewer* getOSGViewer(){ return this; }
    osg::Group* getRoot(){ return m_pRoot; }

protected:
    // 看这里,这是关键,即每帧刷新的操作有这里来完成,使用的思路和QGraphicsView体系中是一样的,控制定时器进行更新
    virtual void paintGL(){ frame(); }
    virtual void timerEvent(QTimerEvent *event){ update(); }

private:
    void init3D();
    osg::ref_ptr<osg::Camera> createCamera(int x, int y, int w, int h);

private:
    osg::ref_ptr<osg::Group> m_pRoot;
};

注意我们的Widget3D直接从osgViewer::Viewer继承了,而在QGraphicsView体系中是设置的视口(setViewPort)。

Widget3D::Widget3D(QWidget *parent)
    : EventAdapter(parent)
{
    init3D();
    this->setMouseTracking(true);
}

Widget3D::~Widget3D()
{

}

void Widget3D::init3D()
{
    m_pRoot = new osg::Group;
    m_pRoot->setName("Root");

    this->setCamera(createCamera(0, 0, width(), height()));
    osg::ref_ptr<osgGA::TrackballManipulator> pManipulator =
        new osgGA::TrackballManipulator;
    this->setCameraManipulator(pManipulator);
    this->addEventHandler(new osgViewer::StatsHandler);
    this->addEventHandler(new osgViewer::ThreadingHandler());
    this->addEventHandler(new osgViewer::HelpHandler);
    this->addEventHandler(new osgGA::StateSetManipulator(this->getCamera()->getOrCreateStateSet()));
    this->setThreadingModel(osgViewer::Viewer::SingleThreaded);

    m_pRoot->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON);
    m_pRoot->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
    this->setSceneData(m_pRoot);

    // 添加cow.osg作为测试
    osg::ref_ptr<osg::Node> pNode = osgDB::readNodeFile("cow.osg");
    osg::ref_ptr<osg::MatrixTransform> matTrans = new osg::MatrixTransform;
    matTrans->addChild(pNode);
    matTrans->setMatrix(osg::Matrix::translate(osg::Vec3d(0, -15, 0)));
    m_pRoot->addChild(matTrans);

    startTimer(10);
}

osg::ref_ptr<osg::Camera> Widget3D::createCamera(int x, int y, int w, int h)
{
    m_pGraphicsWindow = new osgViewer::GraphicsWindowEmbedded(x, y, w, h);
    osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
    osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
    traits->windowDecoration = true;
    traits->x = x;
    traits->y = y;
    traits->width = w;
    traits->height = h;
    traits->doubleBuffer = true;
    traits->sharedContext = 0;

    osg::ref_ptr<osg::Camera> camera = new osg::Camera;
    camera->setGraphicsContext(m_pGraphicsWindow);
    camera->setClearColor(osg::Vec4(0.3, 0.3, 0.6, 0.8));
    camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));
    camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    camera->setProjectionMatrixAsPerspective(
        30.0f, static_cast<double>(traits->width) / static_cast<double>(traits->height), 1.0f, 10000.0f);

    return camera.release();
}
OSG开发中,有时候需要将OSG的场景嵌入QT应用程序中。常见的做法是使用osgQt库来实现这一功能,但是有时候也可以不使用osgQt重写类来嵌入QT应用程序。 在不使用osgQt的情况下,我们可以通过以下几个步骤来实现OSG场景的嵌入。 首先,需要在QT应用程序中创建一个QOpenGLWidget控件,用于显示OSG场景。接着,我们需要创建一个OSG的GraphicsWindowOpenGL对象,将其与QOpenGLWidget控件进行绑定。 然后,我们需要创建一个OSG的Camera对象,并将其设置为主相机。同时,我们需要创建一个OSG的Viewer对象,将之前创建的GraphicsWindowOpenGL对象作为参数传入。 接着,我们可以开始创建场景,并将其添加到Viewer对象中。 在QT应用程序中,我们可以通过重写QOpenGLWidget的resizeGL()函数和paintGL()函数来设置场景的大小和绘制场景。 最后,我们需要在QT应用程序中启动一个定时器,不断更新和绘制场景。可以通过调用Viewer对象的frame()函数来实现。 通过以上的步骤,我们可以实现在QT应用程序中嵌入OSG场景的效果,而不使用osgQt库。 不使用osgQt重写类嵌入QT应用程序的好处是简化了开发过程,并且提供了更多灵活性。我们可以更加自由地控制场景的绘制和更新,以及与其他QT控件的交互。 当然,osgQt库也提供了更多的功能和封装,适用于更复杂的场景嵌入需求。在选择是否使用osgQt时,可以根据具体的开发需求和项目要求进行取舍。
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值