OpenSceneGraph: Manage Windows and Display Modes

  • Tutorial
image

Introduction


We have already said that the osg :: Camera class manages the associated OpenGL graphics context. The graphic context encapsulates information about how and where objects are drawn and which state attributes apply to them. A context is a graphic window, or rather, its client area, or an OpenGL pixel buffer that stores pixel data without transferring it to the frame buffer.

OSG uses the osg :: GraphicsContext class to represent the abstract graphics context, and the osg :: GraphicsWindow class to represent the abstract graphics window. The latter has a getEventQueue () method for managing events from GUI elements. Generally speaking, graphical context is a platform-specific concept, so most of the work on creating a window and associating its context with the OpenGL context, OSG takes over. When you call the createGraphicsContext () method of the osg :: GraphicsContext () class, the required code (and not a little, believe me!) Will be generated by the preprocessor automatically, depending on the platform. All we have to do is pass an osg :: GraphicsContex :: Traits argument to this method, containing a description of which window we want to receive.

1. Class osg :: DisplaySettings


OSG allows the developer to control the global display settings, on the basis of which cameras, viewers and scene elements are rendered. For this purpose, the singleton pattern is used, that is, a unique object containing these settings, implemented in the form of the osg :: DisplaySettings class, which can be accessed from anywhere in the program. Therefore, from our application, we can change these settings at any time.

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

Singleton osg :: DisplaySettings contains settings that are applied to newly created rendering devices, the OpenGL context of the graphics window. You can vary the following parameters:

  1. setDoubleBuffer () - enable / disable double buffering. Enabled by default.
  2. setDepthBuffer () - enable / disable depth buffer. By default enabled.
  3. Set the alpha buffer (alpha buffer), stencil buffer (stencil buffer), accumulation buffer by using methods of the type setMinimumNumAlphaBits (). By default, all parameters are 0.
  4. Allowing to use anti-aliasing and its depth using the setNumMultiSamples () method. The default is 0.
  5. Enable stereo mode. Off by default.

Consider the use of this singleton on the example of smoothing

Singleton osg :: DisplaySettings example
main.h

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

main.cpp

#include"main.h"intmain(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();
}


Only one challenge is important here.

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

- setting the smoothing parameter, which can take the values ​​2, 4 and 6, depending on the graphics device used. Notice how the blade of the screw of the cessna looks without the use of smoothing



and after its application



2. Switch to windowed mode


The osgViewer :: Viewer class can be very quickly reconfigured for display in windowed mode. As you noticed, all our previous examples were displayed in full screen. To switch the viewer to windowed mode, there is the setUpViewInWindow () method, which takes as its parameters the coordinates of the upper left corner of the window, its width and height in pixels

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

Optionally, this method takes the fifth parameter — the number of the screen to which the window should be displayed, in case you have more than one monitor. Surely working with multiple monitors in Windows, you observed that the scene is spreading out to all monitors in full screen mode (this is not observed in Linux).

In addition, in the project settings, you can set the OSG_WINDOW environment variable in such a way



that it will be equivalent to calling setUpViewInWindow (), which in this case can also not be performed.



To explicitly specify the screen to which the viewer should be displayed in full screen mode, you can use the setUpViewOnSingleScreen () method by specifying the screen number as a parameter (default 0).

OSG also supports demo spherical displays. You can use the setUpViewFor3DSphericalDisplay () method to customize the display on this display.

3. Composite Viewer


The osgViewer :: Viewer class manages one view that displays one scene graph. Besides it, there is a class osgViewer :: CompositeViewer which supports several views and several scenes. It has the same run (), frame () and done () methods to control the rendering process, but it allows you to add and remove independent views using the addView () and removeView () methods, as well as get the views from their index using the getView method () The view object is described by the osgViewer :: View class.

The osgViewer :: View class is the base class of the osgViewer :: Viewer class. It allows you to add a root node with scene data, a camera's manipulator and event handlers. The main difference between this class (view) and the viewer class is that it does not allow rendering the scene with run () or frame () calls. A typical script for adding a view looks like this.

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

Composite viewer allows you to display one scene in different angles, displaying these angles in different windows. It also allows you to display independent scenes in different windows. Let's write a simple example of using a composite viewer.

Composite example
main.h

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


Creating a separate view is placed in a function that takes as parameters the position and size of the window, as well as the scene as a pointer to its root node.

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

Here we create a view managed by a smart pointer to the object osgViewer :: View

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

set the data of the displayed scene and the windowed display mode in the window with the specified position and size

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

The view is returned from the function according to the rules for returning smart pointers.

return view.release();

Now in the main program we load three different models.

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

we create three different types

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

create a composite viewer and add previously created views to it

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

and we start rendering in exactly the same way as we did in the case of a single scene.

return viewer.run();

Everything! When you run the program, we get three different windows. The contents of each window can be managed independently. Any of the windows can be closed in the standard way, and exit the entire application by pressing Esc.



3. Class osg :: GraphicsContext :: Traits


The word "traits" in English means "features." So, the above class describes the features of the future window, and contains all the properties for describing the graphic context. It differs from the osg :: DisplaySettings class, which controls the characteristics of all graphics contexts for newly created cameras. The main public properties of this class are listed in the table below.

Class attributeType ofDefault valueDescription
xint0Initial horizontal position of the window
yint0Initial vertical position of the window
widthint0Window width
heightint0Window height
windowNamestd :: string""Window title
windowDecorationboolfalseWindow title display flag
redunsigned inteightThe number of bits of red in the OpenGL color buffer
greenunsigned inteightThe number of bits of green in the OpenGL color buffer
blueunsigned inteightThe number of bits of blue in the OpenGL color buffer
alphaunsigned inteightThe number of bits in the OpenGL alpha buffer
depthunsigned int24The number of bits in the OpenGL depth buffer
stencilunsigned int0The number of bits in the stencil buffer OpenGL
doubleBufferboolfalseUse double buffer
samplesunsigned int0The number of primitive smoothing
quadBufferStereoboolfalseUse quad stereo buffer (for NVidia hardware)
inheritedWindowDataosg :: ref_ptrNullThe data descriptor associated with the window

To initialize the object Traits, you must run the following code

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

4. Configure the OSG application window


To create a window with the specified characteristics, you must do the following steps:

  1. Configure an object of type osg :: GraphicsContext :: Traits
  2. Create graphic window context
  3. Associate this graphic context with the camera.
  4. Make the camera main for the viewer

Traits example
main.h

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

main.cpp

#include"main.h"intmain(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();
}


To set the window settings, create an instance of the osg :: GraphicsContext :: Traits class and initialize it with the parameters we need

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;

After that we create a graphic context, passing as a pointer to the traits as settings

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

Create a camera

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

Associate the camera with the created graphics context.

camera->setGraphicsContext(gc);

Adjust the viewport, set the buffer cleaning mask, set the cleaning color

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

Adjusting the perspective projection matrix

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

Do not forget to turn on the depth test, for the correct display of faces

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

Load model aircraft

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

We configure and launch the viewer, indicating the camera we set up as the main camera

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

At the output, we have a window with the required parameters.



The window title is not displayed because in the settings of my window manager this function is disabled. If you run the example in Windows or Linux with different settings, the title will be in place.

To be continued...

Also popular now: