1-OSG 单视图

1-OSG 单视图

平台准备

  • 软件框架: 基于qt5.9
  • OSG版本 3.6.4
  • 操作系统 win10

实现功能

  • 单窗口单视图
  • 加入漫游器

基本实现思路

  1. 实现上面功能,我们需要以下成员
       osg::ref_ptr<CGE::GraphicsWindowEmbeddedCustom> _graphicsWindow;
       osg::ref_ptr<osgViewer::Viewer> _viewer;

        osg::ref_ptr<osg::Group> _root;
        osg::ref_ptr<osg::Node> _model;
        osg::ref_ptr<osgGA::TrackballManipulator> _trackball;
        osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> _keyswitchManipulator;

        RenderingThread* _threadHandle;
  1. 需要特别说明的:
  • GraphicsWindow 选择, 如下图所示,在这里插入图片描述

在windows 中可以选择使用 osgViewer::GraphicsWindowWin32 或者 osgViewer::GraphicsWindowEmbedded;
[1]osgViewer::GraphicsWindowWin32:内部已经实现了从窗口创建到渲染上下文的创建(HRC), 我们需要做的只是将参数通过osg::GraphicsContext::Traits,传入即可。如果窗口已经创建,将句柄(HWND)传入,则内部则不会在进行窗口创建。
[2]osgViewer::GraphicsWindowEmbedded: 以上需要由我们自己创建。本文采用了了这个GraphicsWindow;
特别注意的:osgViewer::GraphicsWindowEmbedded 在进行多线程模式时,需要在线程创建上下文,如果在这之前创建,那么在线程的再次获取上下文会失败。 osg error: opengl version test failed, requires valid graphics context;

  • 避免窗口闪烁:
    (1)软件基于Qt窗口组件,避免Qt绘制引擎绘制导致闪烁
virtual QPaintEngine* paintEngine() const {
	return nullptr;
}

(2) 在窗口大小发生变化或者窗口重绘时时,需要立马更新视图

virtual void paintEvent( QPaintEvent* ) {
	_viewer->frame();
}
virtual void resizeEvent( QResizeEvent* ) {
	_viewer->frame();
}

(3) 需要开启一个线程,或者开启定时器,不断更新视图; 如下采用线程方式;特别注意: 如果主线程和这个线程同时调用刷新,则需要加锁
RenderingThread* _threadHandle:

void RenderingThread::run()
{
    if ( !_viewer )
    {
        _done = true;
        return;
    }

    do
    {
        //_ptr->PreFrameUpdate();
        _viewer->frame();
        //_ptr->PostFrameUpdate();
    } while ( !testCancel() && !_viewer->done() && !_done );
}
  • 在调用qt函数获取窗口大小时,需要注意qt窗口是由局部坐标和全局坐标。另外,在创建OpenGl视口时,左下角是坐标原点,如果没有特别需求,默认坐标原点为(0, 0)即可:
void Window3d::resizeEvent(QResizeEvent *)
{
    int width = this->rect().right() - this->rect().left();
    int higth = this->rect().bottom() - this->rect().top();
    int x = 0;
    int y = 0;
    this->getEventQueue()->windowResize(x, y, width, higth);
     _graphicsWindow->resized(x, y, width, higth);
     osg::Camera* camera = _viewer->getCamera();
     camera->setViewport(x, y, width, higth);

//使用这一部分代码,则视口坐标原点是有问题的。
//    this->getEventQueue()->windowResize(this->x(), this->y(), this->width(), this->height());
//     _graphicsWindow->resized(this->x(), this->y(), this->width(), this->height());
//     osg::Camera* camera = _viewer->getCamera();
//     camera->setViewport(this->x(), this->y(), this->width(), this->height());

}

(4) 特别注意,osg集成到其它GUI开发的应用程序时,如Qt , MFC, WPF 等时,需要留意osg渲染是使用单独线程的,而一般应用程序GUI消息循环有单独的线程分发运行的; 因此,对osg对象的操做,在接收到GUI触发事件后,需要将事件转换到osg的消息队列中。 否则在不同线程操作同一个对象,在不加锁情况下,结果是未知的;
当然,应用程序其它线程的操作也是同理。
继承osg最常见的多线程错误之一: 在group节点遍历时, vector iterator not increamentable;
当然还有更多不可预期的异常会发生…
方法:

  1. 使用回调函数: 向ogs::Viewer中添加事件回调对象, 或者向Node节点添加更新回调回调对象
  2. 使用osg的访问器机制: 继承osg::NodeVistor , 重写osg::NodeVisitor::apply(…) 函数




## 实现效果
![在这里插入图片描述](https://img-blog.csdnimg.cn/7fde2ab2f947427e8dcc304f3664b89d.gif#pic_center)


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值