OpenSceneGraph:管理Windows和显示模式

图片

引言


我们已经说过osg :: Camera类管理关联的OpenGL图形上下文。 图形上下文封装了有关如何绘制对象以及在何处绘制对象以及将哪些状态属性应用于对象的信息。 上下文被理解为图形窗口,或者更确切地说是其客户区域或OpenGL像素缓冲区,它存储像素数据而不将其传输到帧缓冲区。

OSG使用osg :: GraphicsContext类表示抽象的图形上下文,并使用osg :: GraphicsWindow类表示抽象的图形窗口。 后者具有用于管理来自GUI元素的事件的getEventQueue()方法。 一般来说,图形上下文是特定于平台的概念,因此OSG负责创建窗口并将其上下文与OpenGL上下文相关联的大部分工作。 当您调用osg :: GraphicsContext()类的createGraphicsContext()方法时,所需的代码(相信很多!)将由预处理器自动生成,具体取决于平台。 我们要做的就是将参数传递给osg :: GraphicsContex :: Traits类型的方法,其中包含对我们要获取的窗口的描述。

1. osg类:: DisplaySettings


OSG允许开发人员根据渲染的相机,查看器和场景元素来管理全局显示设置。 为此,使用单例模式,即包含这些设置的唯一对象,以osg :: DisplaySettings类的形式实现,可以从程序中的任何位置进行访问。 因此,从我们的应用程序中,我们可以随时更改这些设置。

osg::DisplaySettings *ds = osg::DisplaySettings::instance(); 

Singleton osg :: DisplaySettings包含适用于新创建的渲染设备的设置,即图形窗口的OpenGL上下文。 您可以更改以下参数:

  1. setDoubleBuffer()-启用/禁用双缓冲。 默认启用。
  2. setDepthBuffer()-启用/禁用深度缓冲区。 默认启用。
  3. 使用setMinimumNumAlphaBits()之类的方法设置alpha缓冲区,模板缓冲区,累积缓冲区的宽度。 默认情况下,所有参数均为0。
  4. 可以使用setNumMultiSamples()方法使用抗锯齿及其深度。 默认值为0。
  5. 打开立体声模式。 默认关闭。

考虑在平滑示例中使用此单例

OSG单例示例:: DisplaySettings
主文件

 #ifndef MAIN_H #define MAIN_H #include <osgDB/ReadFile> #include <osgViewer/Viewer> #endif 

main.cpp

 #include "main.h" int main(int argc, char *argv[]) { (void) argc; (void) argv; osg::DisplaySettings::instance()->setNumMultiSamples(6); osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("../data/cessna.osg"); osgViewer::Viewer viewer; viewer.setSceneData(model.get()); return viewer.run(); } 


这里必不可少的只是一个挑战。

 osg::DisplaySettings::instance()->setNumMultiSamples(6); 

-设置平滑参数,根据所使用的图形设备,该参数可以取值为2、4和6。 注意在不进行平滑处理的情况下塞纳叶片的外观



及其应用后



2.切换至视窗模式


可以非常快速地将osgViewer :: Viewer类重新配置为以窗口模式显示。 如您所见,我们之前的所有示例均以全屏显示。 要将查看器切换到窗口模式,有setUpViewInWindow()方法,该方法将窗口左上角的坐标,其宽度和高度(以像素为单位)作为参数。

 viewer.setUpViewInWindow(50, 50, 800, 600); 

(可选)此方法接受第五个参数-如果您有多个监视器,则应在其上显示窗口的屏幕编号。 可以肯定的是,在Windows中使用多个监视器时,您观察到场景以全屏模式传播到所有监视器(在Linux中没有观察到)。

此外,在项目设置中,可以通过这种方式设置环境变量OSG_WINDOW



这等效于调用setUpViewInWindow(),在这种情况下可能不会执行。



要明确指定在全屏模式下显示查看器的屏幕,可以通过将屏幕编号指定为参数(默认为0)来使用setUpViewOnSingleScreen()方法。

OSG还支持演示球形显示器。 您可以使用setUpViewFor3DSphericalDisplay()方法来自定义此类显示。

3.复合查看器


osgViewer :: Viewer类控制显示单个场景图的单个视图。 除此之外,还有一个osgViewer :: CompositeViewer类,它支持多个视图和多个场景。 它具有相同的run(),frame()和done()方法来控制渲染过程,但是它允许您使用addView()和removeView()方法添加和删除独立视图,以及使用getView方法按其索引获取视图。 ()。 视图对象由osgViewer :: View类描述。

osgViewer :: View类是osgViewer :: Viewer类的基类。 它使您可以添加带有场景数据,摄像机操纵器和事件处理程序的根节点。 此类(视图)和查看器类之间的主要区别在于,它不允许使用run()或frame()调用渲染场景。 一个典型的视图添加场景如下所示

 osgViewer::CompositeViewer multiviewer; multiviewer.addView( view ); 

复合查看器允许您以不同角度显示一个场景,并在不同窗口中显示这些角度。 它还允许您在不同的窗口中显示独立的场景。 让我们写一个使用复合查看器的简单示例

复合例子
主文件

 #ifndef MAIN_H #define MAIN_H #include <osgDB/ReadFile> #include <osgViewer/CompositeViewer> #endif 

main.cpp

 #include "main.h" //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ osgViewer::View *createView(int x, int y, int w, int h, osg::Node *scene) { osg::ref_ptr<osgViewer::View> view = new osgViewer::View; view->setSceneData(scene); view->setUpViewInWindow(x, y, w, h); return view.release(); } //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ int main(int argc, char *argv[]) { (void) argc; (void) argv; osg::ref_ptr<osg::Node> model1 = osgDB::readNodeFile("../data/cessna.osg"); osg::ref_ptr<osg::Node> model2 = osgDB::readNodeFile("../data/cow.osg"); osg::ref_ptr<osg::Node> model3 = osgDB::readNodeFile("../data/glider.osg"); osgViewer::View *view1 = createView(50, 50, 320, 240, model1); osgViewer::View *view2 = createView(380, 50, 320, 240, model2); osgViewer::View *view3 = createView(185, 330, 320, 240, model3); osgViewer::CompositeViewer viewer; viewer.addView(view1); viewer.addView(view2); viewer.addView(view3); return viewer.run(); } 


我们将在一个单独的视图中创建一个函数,该函数将窗口的位置和大小以及场景作为指向其根节点的指针作为参数

 osgViewer::View *createView(int x, int y, int w, int h, osg::Node *scene) { osg::ref_ptr<osgViewer::View> view = new osgViewer::View; view->setSceneData(scene); view->setUpViewInWindow(x, y, w, h); return view.release(); } 

在这里,我们创建一个由智能指针控制的视图,该指针指向osgViewer :: View对象

 osg::ref_ptr<osgViewer::View> view = new osgViewer::View; 

在窗口中以指定的位置和大小设置显示场景的数据和窗口显示模式

 view->setSceneData(scene); view->setUpViewInWindow(x, y, w, h); 

我们根据返回智能指针的规则从函数返回视图

 return view.release(); 

现在在主程序中,我们加载了三种不同的模型

 osgViewer::View *view1 = createView(50, 50, 320, 240, model1); osgViewer::View *view2 = createView(380, 50, 320, 240, model2); osgViewer::View *view3 = createView(185, 330, 320, 240, model3); 

创建三种不同的类型

 osgViewer::View *view1 = createView(50, 50, 320, 240, model1); osgViewer::View *view2 = createView(380, 50, 320, 240, model2); osgViewer::View *view3 = createView(185, 330, 320, 240, model3); 

创建一个复合查看器并向其添加以前创建的视图

 osgViewer::CompositeViewer viewer; viewer.addView(view1); viewer.addView(view2); viewer.addView(view3); 

并以与在一个场景中完全相同的方式运行渲染

 return viewer.run(); 

仅此而已! 程序启动时,我们将获得三个不同的窗口。 每个窗口的内容可以独立控制。 可以以标准方式关闭任何一个窗口,然后按Esc完全退出应用程序。



3. osg :: GraphicsContext :: Traits类


英语翻译中的“特征”一词意为“特征”。 因此,上述类描述了Future窗口的功能,并包含了用于描述图形上下文的所有属性。 它不同于osg :: DisplaySettings类,该类控制新创建的摄像机的所有图形上下文的特征。 下表列出了此类的主要公共属性。

类属性型式预设值内容描述
X整型0窗口的初始水平位置
ÿ整型0窗口的初始垂直位置
宽度整型0窗宽
身高整型0窗高
windowNamestd ::字符串窗口标题
windowDecoration布尔错误的窗口标题显示标志
红色的无符号整数8OpenGL颜色缓冲区中红色的位数
绿色的无符号整数8OpenGL颜色缓冲区中绿色的位数
蓝色的无符号整数8OpenGL颜色缓冲区中蓝色的位数
阿尔法无符号整数8OpenGL alpha缓冲区中的位数
深度无符号整数24OpenGL深度缓冲区中的位数
模具无符号整数0OpenGL模板缓冲区中的位数
doubleBuffer布尔错误的使用双缓冲
样本无符号整数0基本平滑数
quadBufferStereo布尔错误的使用四路立体声缓冲器(用于NVidia设备)
InheritedWindowDataosg :: ref_ptr空值与窗口相关的数据描述符

要初始化Traits对象,请执行以下代码

 osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits; traits->x = 50; traits->y = 100; ... 

4.设置OSG应用程序窗口


要创建具有指定特征的窗口,必须执行以下步骤:

  1. 配置类型为osg :: GraphicsContext :: Traits的对象
  2. 创建图形窗口上下文
  3. 将此图形上下文链接到摄像机
  4. 使相机成为主要观看者

特性示例
主文件

 #ifndef MAIN_H #define MAIN_H #include <osg/GraphicsContext> #include <osgDB/ReadFile> #include <osgViewer/Viewer> #endif 

main.cpp

 #include "main.h" int main(int argc, char *argv[]) { (void) argc; (void) argv; osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits; traits->x = 50; traits->y = 50; traits->width = 800; traits->height = 600; traits->windowName = "OSG application"; traits->windowDecoration = true; traits->doubleBuffer = true; traits->samples = 4; osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get()); osg::ref_ptr<osg::Camera> camera = new osg::Camera; camera->setGraphicsContext(gc); camera->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); camera->setClearColor( osg::Vec4(0.2f, 0.2f, 0.4f, 1.0f) ); double aspect = static_cast<double>(traits->width) / static_cast<double>(traits->height); camera->setProjectionMatrixAsPerspective(30.0, aspect, 1.0, 1000.0); camera->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON); osg::ref_ptr<osg::Node> root = osgDB::readNodeFile("../data/cessna.osg"); osgViewer::Viewer viewer; viewer.setCamera(camera.get()); viewer.setSceneData(root.get()); return viewer.run(); } 


要设置窗口首选项,请创建osg :: GraphicsContext :: Traits类的实例,并使用我们需要的参数对其进行初始化

 osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits; traits->x = 50; traits->y = 50; traits->width = 800; traits->height = 600; traits->windowName = "OSG application"; traits->windowDecoration = true; traits->doubleBuffer = true; traits->samples = 4; 

之后,我们通过传递指向特征的指针作为设置来创建图形上下文

 osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get()); 

创建一个相机

 osg::ref_ptr<osg::Camera> camera = new osg::Camera; 

我们将相机与创建的图形上下文相关联

 camera->setGraphicsContext(gc); 

设置视口,设置缓冲区清洁蒙版,设置清洁颜色

 camera->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); camera->setClearColor( osg::Vec4(0.2f, 0.2f, 0.4f, 1.0f) ); 

设置透视投影矩阵

 double aspect = static_cast<double>(traits->width) / static_cast<double>(traits->height); camera->setProjectionMatrixAsPerspective(30.0, aspect, 1.0, 1000.0); 

不要忘记启用深度测试,以正确显示面部

 camera->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON); 

装载飞机模型

 osg::ref_ptr<osg::Node> root = osgDB::readNodeFile("../data/cessna.osg"); 

我们配置并启动查看器,以主摄像机的质量指示我们配置的摄像机

 osgViewer::Viewer viewer; viewer.setCamera(camera.get()); viewer.setSceneData(root.get()); return viewer.run(); 

在出口处,我们有一个带有必需参数的窗口



不显示窗口标题,因为在我的窗口管理器的设置中禁用了此功能。 如果您在具有不同设置的Windows或Linux上运行示例,则标题将位于其位置。

待续...

Source: https://habr.com/ru/post/zh-CN437764/


All Articles