OSG 渲染(1) 多视图的实现方法

一般多视图、视口在CAD、仿真领域里用的比较多,游戏里用的相对较少。尤其是CAD,要求在多视口内用不同的渲染模式来显示零件。比如,在单视图内用多视口方式,分别用着色模式,线框消隐模式来绘制显示模型。

这里提到视口,视图,在不同的软件中因其定义实现的方式不同,显得比较混乱,有时两者不同,有时两者又等价!按我自己理解,一个窗口内划分成几个部分,如果每个子区域包括业务处理逻辑(如事件处理,在子区域内平移、旋转、缩放对象,其它区域不受影响),这个子区域可以看成是视图;如果子区域只负责显示模型,不负责事件处理,该子区域可以看成视口,也就是说将视口看成功能弱于视图的子显示区域。这只是个人看法,你完全可以将子显示区域都定义为视口,例如 AutoCAD。

OSG视图显示关键几个类:

osg::View

该类为视图组织管理最基础的类,管理主、从相机,光照模式(天光,头顶光,无光照)。

osgViewer::View : public osg::View, public osgGA::GUIActionAdapter

该类扩展了基础视图类,加入了场景数据、窗口事件、视图配置的管理功能,渲染器(Renderer)也在此创建。

osgViewer::ViewerBase

该类为更高层的视图管类,使视图具有多线程渲染的能力,并管理渲染设备上下文的初始化,渲染线程的管理、调度,视图更新的三个阶段:事件更新过程【eventTraversal()】,状态更新过程【updateTraversal()】,及渲染更新过程【renderingTraversals()】。

ViewerBase 派生出两个子类:单视图视景器 osgViewer::Viewer, 多视图视景器 osgViewer::CompositeViewer。

osgViewer::Viewer : public ViewerBase, public osgViewer::View

osgViewer::CompositeViewer : public ViewerBase

从上面两类继承关系,我们可以看出,osgViewer::CompositeViewer 是没有渲染能力但具有上下文管理,线程调度管理的Viewer 的容器类, 渲染内容的输出由osgViewer::Viewer 来完成。

从以上视图相关类的继承关系可以看出,有三种方式可以实现多视图:

如果需要子视图功能完备,能够处理自己的交互事件,我们就用CompositeViewer 来作为主视图,再添加Viewer来呈现不同的内容。

如果只需要在视图内,以不同的视角观察模型,我们用osgViewer::Viewer 来作为主视图,在添加不同的slave camera来实现。

如果创建一个主窗口,再创建多个windows窗口,用splitecontainer控件分割,每个子窗口用osgViewer::Viewer 做为主视图,也可以实现多视图。但这种方式,需要消耗更多的硬件资源,且OpenGL 层面的显示数据不能公用。

 

多视图的实现涉及到几个细节方面的问题:

模型数据的复用?

对象显示状态如何分离?

例如,你在一个视图内高亮一个对象,因为模型及模型显示属性数据是复用的,另一个视图内相关的对象也会高亮。这在模型显示属性在不同视图内一致时没有问题,而且是我们想要的显示效果。但当不同视图内对象显示状态不一致时,就不合适了。例如对象在一个子窗口内是可见的,另一个窗口内是不可见的。

osg 要求当前上下文一定要有一个View, 否则停止渲染。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
在使用 Qt 进行多线程渲染时,可以使用 Qt 的 QThread 类来创建多个线程,然后在每个线程中执行渲染任务。但是,由于 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 线程退出。 需要注意的是,上面的示例代码只是一个简单的示例,并没有考虑线程安全和线程同步的问题。在实际应用中,需要根据具体情况进行更加完善的设计。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值