【 OSG渲染之《最长的一帧》frame() 函数和 viewerInit() 函数介绍】

OSG渲染之最长的一帧笔记系列文章

第一章 第一日内容 frame() 函数和 viewerInit() 函数介绍


前言

本系列文章主要是利用王锐老师《最长的一帧》撰写读书笔记,以便更加简洁且有条理地去重复查阅和理解书籍内容。


一、frame()函数

所属模块和文件:osgViewer/ViewerBase.cpp。
frame() 是 ViewerBase类的成员函数,而非 Viewer 类。因此,无论对于单视景器的 Viewer 类,还是多视景器的CompositeViewer 类,frame 函数的内容都是相同的(因为它们都没有再重写这个函数的内容)。

代码如下:

void ViewerBase::frame(double simulationTime)
{
    if (_done) return;
    // OSG_NOTICE<<std::endl<<"CompositeViewer::frame()"<<std::endl<<std::endl;
    //如果这是仿真系统启动后的第一帧
    if (_firstFrame)
    {
        viewerInit();
        //此时如果还没有执行 realize()函数,则执行它
        if (!isRealized())
        {
            realize();
        }
        _firstFrame = false;
    }
    advance(simulationTime);
    /*这个函数将负责处理系统产生的各种事件,诸如鼠标的移动,点击,键盘的响应,窗口的关闭等等,
    以及摄像机与场景图形的事件回调(EventCallback)。*/
    eventTraversal();
    /*这个函数负责遍历所有的更新回调(UpdateCallback);除此之外,它的另一个重要任务就是负责更 
    新 DatabasePager 与 ImagePager 这两个重要的分页数据处理组件。*/
    updateTraversal();
    /* 这里将使用较为复杂的线程处理方法,完成场景的筛选(cull)和绘制(draw)工作*/
    renderingTraversals();
}

二、Viewer::viewerInit()函数

所属模块和文件:osgViewer/View.cpp。
Viewer::viewerInit 函数只做了一件事,就是调用 View::init()函数,而这个 init 函数的工作似乎也是一目了然的:无非就是完成视景器的初始化工作而已。

代码如下:

void View::init()
{
    OSG_INFO<<"View::init()"<<std::endl;
    osg::ref_ptr<osgGA::GUIEventAdapter> initEvent = _eventQueue->createEvent();
    //随后这个新事件的类型被指定为 FRAME 事件,即每帧都会触发的一个事件。
    initEvent->setEventType(osgGA::GUIEventAdapter::FRAME);
    if (_cameraManipulator.valid())
    {
        _cameraManipulator->init(*initEvent, *this);
    }
}

1、_eventQueue 它用于储存该视景器的事件队列。OSG中代表事件的类osgGA::GUIEventAdapter,它可以用于表达各种类型的鼠标、键盘、触压笔和窗口事件。在用户程序中,我们往往通过继承 osgGA::GUIEventHandler 类,并重写 handle 函数的方法,获取实时的鼠标 / 键盘输入,并进而实现相应的用户代码(参见osgkeyboardmouse)。
_eventQueue 除了保存一个 GUIEventAdapter 的链表之外,还提供了一系列对链表及其元素的操作函 数,这其中,createEvent 函数的作用是分配和返回一个新的 GUIEventAdapter事件的针。
2、cameraManipulator 是视景器中所用的场景漫游器的实例。通常我们都会使用 setCameraManipulator 来设置这个变量的内容,例如轨迹球漫游器(TrackballManipulator)可以使用鼠标拖动来观察场景,而驾驶漫游器(DriveManipulator)则使用类似于汽车驾驶的效果来实现场景的漫游。
3、上面的代码将新创建的 FRAME 事件和 Viewer 对象本身传递给_cameraManipulator 的init 函数,不同的漫游器(如 TrackballManipulator、DriveManipulator)会重写各自的 init 函数,实现自己所需的初始化工作。如果读者希望自己编写一个场景的漫游器,那么覆写并使用 osgGA::MatrixManipulator::init 就可以灵活地初始化自定义漫游器的功能了,它的调用时机就在这里。

总结

以上就是今天要讲的内容,本文仅仅简单介绍了osgGA::EventQueue::createEvent,osgGA::MatrixManipulator::init,osgViewer::View::init,osgViewer::Viewer::viewerInit的内容。

  • 32
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用 Qt 进行多线程渲染时,可以使用 QtQThread 类来创建多个线程,然后在每个线程中执行渲染任务。但是,由于 Qt 的 GUI 线程不是线程安全的,因此需要使用信号和槽机制来进行线程间通信。 在使用 OpenSceneGraph 进行渲染时,可以使用 osgViewer::Viewer 类来创建视图窗口,并在其中添加多个场景。然后,可以使用 osgViewer::Viewer::frame() 函数在每个线程中循环渲染每个场景。 下面是一个简单的示例代码: ```cpp #include <QThread> #include <osgViewer/Viewer> class RenderThread : public QThread { public: RenderThread(osgViewer::Viewer* viewer) : _viewer(viewer) {} private: void run() override { while (!isInterruptionRequested()) { _viewer->frame(); } } osgViewer::Viewer* _viewer; }; int main(int argc, char** argv) { osgViewer::Viewer viewer; viewer.setSceneData(createSceneGraph()); viewer.setUpViewInWindow(100, 100, 800, 600); RenderThread thread1(&viewer); RenderThread thread2(&viewer); thread1.start(); thread2.start(); int ret = QApplication(argc, argv).exec(); thread1.requestInterruption(); thread2.requestInterruption(); thread1.wait(); thread2.wait(); return ret; } ``` 在上面的示例代码中,我们创建了两个 RenderThread 线程,并将 osgViewer::Viewer 对象传递给它们。然后,在每个 RenderThread 线程中,我们使用 while 循环调用 osgViewer::Viewer::frame() 函数来不断渲染场景。最后,在主线程中启动 QApplication 并等待 RenderThread 线程退出。 需要注意的是,上面的示例代码只是一个简单的示例,并没有考虑线程安全和线程同步的问题。在实际应用中,需要根据具体情况进行更加完善的设计。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值