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();
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-11 22:51:23

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

使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 选择调用的进程为 24 i386 getuid sys_getuid1647 i386 getgid sys_getgid16 使用库函数API方式 使用C代码中嵌入汇编代码方式

创建对象的第二种方式:克隆clone,要实现Cloneable接口

1 ackage com.wisezone.clone; 2 3 /** 4 * 空接口: 5 * 标识,告诉JVM,通行 6 * 1.克隆 7 * 2.序列化 8 * 9 * 创建对象的第二种方式:克隆clone,要实现Cloneable 10 * @author 王东海 11 * @2017年4月15日 12 */ 13 public class TestClone implements Cloneable 14 { 15 public String name; 16 17 public s

实验--使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用(杨光)

使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 攥写人:杨光  学号:20135233 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验要求: 选择一个系统调用(13号系统调用time除外),系统调用列表参见http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/syscalls/sys

js最基础知识回顾2(函数传参,操作属性的第二种方式,提取行间事件,操作一组元素,this,焦点问题和鼠标按下抬起,选项卡)

一.函数传参     1.函数传参:参数就是占位符----函数里定不下来的东西 a. var a1=function(){ alert(123); }; function a(f){ // 相当于 f=a1 f(); }; a(a1); b.  function skip(skipPath){  //换肤 var oLink1 = document.getElementById('link1'); oLink1.href=skipPath; } c.   function setStyle(na

用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

姓名:王晨光 学号:20133232 王晨光 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 本周的实验相比较前面3次实验较为容易理解,这次实验的浅析了系统调用的工作过程,通过用库函数API和C代码嵌入汇编代码两种方式使用同一个系统调用. 我这次实验选择了20号系统调用getpid来获取进程ID.首先我先在网上查阅了getpid函数是用来获取目前进程的ID,许多程序利用取到的此值

Java创建线程的第二种方式:实现runable接口

/*需求:简单的卖票程序多个窗口买票 创建线程的第二种方式:实现runable接口 *//*步骤1.定义类实现Runable接口2.覆盖Runable接口中的run方法    将线程要运行的代码存放在该run方法中 3.通过Thread类建立线程对象4.将Runable接口的子类对象作为实际参数传递给Thread类的构造函数  为什么要将Runable接口的子类对象传递给Thread的构造函数.  因为,自定义的run方法所属的对象是Runable接口的子类对象  所以要让线程去指定对象的Run

创建线程的第二种方式------实现Runnable接口的方式

package cn.itcast.demo16.Demo07.Runnable; /** * @author newcityman * @date 2019/7/22 - 23:17 */public class RunnableImpl implements Runnable { @Override public void run() { for (int i = 0; i <20 ; i++) { System.out.println(Thread.currentThread().getN

linux内核分析第四周-使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

本周作业的主要内容就是采用gcc嵌入汇编的方式调用system call.系统调用其实就是操作系统提供的服务.我们平时编写的程序,如果仅仅是数值计算,那么所有的过程都是在用户态完成的,但是我们想将变量打印在屏幕上,就必须调用printf,而printf这个函数内部就使用了write这个系统调用.操作系统之所以以system call的方式提供服务,是因为如果程序员能够任意操作OS所有的资源,那么将无比危险,所以OS设计出了内核态和用户态. 我们平时编程都是在用户态下,如果我们想要调用系统资源,那

Webform中Repeater控件--绑定嵌入C#代码四种方式

网页里面嵌入C#代码用的是<% %>,嵌入php代码<?php ?> 绑定数据的四种方式: 1.直接绑定 <%#Eval("Code") %> 2.调用函数 <%#ShowSex()%> 3.显示外键关系列 <%#Eval("Nation1.Name") %> 4.格式化显示 <%#Eval("Birthday","{0:yyyy年MM月dd日}") %>