OpenSceneGraph is a cross-platform open source library for developing high-performance 3D applications. This is not a game engine that connects the user hand and foot with the limitations laid down in it, namely, the library - a set of useful modules that work well both alone and in assembly.

The core of OpenSceneGraph, the actual graph of the scene, is a rather thin wrapper around OpenGL that allows you to set a hierarchy of objects and perform any desired transformations on them:
- change the characteristics of nodes (move objects in space, assign materials to them, lighting properties, shaders, and other modes and attributes of OpenGL);
- rebuild the tree in any desired way (create and delete objects, link them to other nodes of the graph);
- do a graph traversal, performing any actions for each node;
- and of course render the scene using OpenGL.
Scene graph in OpenSceneGraph
Each node of the scene graph is an instance of one of the descendants of the Node class. Arrows are parent-child relationships:
')

Nodes with children are called groups. An ordinary Group does nothing with its children - they will all be rendered as they are. However, inheritors of the Group class may have additional behavior. For example, MatrixTransform inherits the Group class, and allows you to apply a transformation matrix to all children at once. For example, if you change the matrix responsible for the tank tower, the tower will spin along with the barrel:

The primitives of drawing OpenSceneGraph are called Drawables. Each Drawable corresponds to some OpenGL drawing primitive: sphere, cube, arbitrary mesh, OpenGL teapot, etc. The Drawables themselves enter the stage only in the Geode container (short for “geometry node”). A geode can hold any number of drawables:

A very important feature of OpenSceneGraph is that any node can have several descendants. This is important in order not to duplicate identical objects and not to waste computer memory and video adapter to store duplicate fragments. For example, a tank has several wheels and several tracks, but since they are the same, you can store them in one instance, and so that they are located in different places of the tank, we will set their position using individual MatrixTransforms:

If we want to make a full-fledged model of a tank that can turn wheels and caterpillars, turn the turret and control the barrel, then we get a graph like this:

To turn the wheels, just change the texture mapping on the left or right wheels. And the user will see that the corresponding wheels are spinning all at once. Similarly with caterpillars - a change in texture can achieve a visible effect of movement.
Two words about memory management
A scene graph can have a very complex structure, and in order to simplify memory management, OpenSceneGraph uses a garbage collector with a reference counter. Each class inheriting osg :: Referenced gets its own reference counter, which is automatically incremented and decremented using the smart pointer system osg :: ref_ptr. Here is a simple example:
{ osg::ref_ptr<osg::Geode> geode = new osg::Geode; }
In this example, a new instance of osg :: Geode is created, a smart pointer is initialized, then the pointer is destroyed, and with it osg :: Geode, since there are no more links to it. When adding children to the group, Drawables in the Geode and all other cross-references between objects of the graph, smart pointers are used. This ensures that when deleting a link to the root node of the graph, all objects will be correctly destroyed.
Hello World
Here is the minimal OpenSceneGraph application:
#include <osgViewer/Viewer> int main() { osgViewer::Viewer viewer; return viewer.run(); }
It uses the osgViewer module, which takes care of opening the graphics window, initializing OpenGL, creating the default camera, initializing the Escape key handler and mouse controller, so that you can move the camera with it. When you start the program, we will see an empty scene, which by Escape closes.
The next step is to create the root node. For example, put in front of viewer.run () the code for creating a sphere:
// Drawable osg::Sphere *shape = new osg::Sphere( osg::Vec3(0.0f, 0.0f, 0.0f), 1.0f); osg::ShapeDrawable *drawable = new osg::ShapeDrawable(shape); // Geode osg::Geode *geode = new osg::Geode; geode->addDrawable(drawable); // viewer.setSceneData(geode);
After starting this application, we will see the scope:

Now you can go to download the font and text output. We need the osgText library, which is responsible for working with text:
osgText::Font *font = osgText::readFontFile( "/usr/share/fonts/truetype/msttcorefonts/arial.ttf"); osgText::Text *text = new osgText::Text; text->setFont(font); text->setAxisAlignment(osgText::Text::XZ_PLANE); text->setText(", !", osgText::String::ENCODING_UTF8); osg::Geode *geode = new osg::Geode; geode->addDrawable(text);
The readFontFile function loads a font from a file, then we create a Text object that is derived from Drawable. This means that it can be added to the Geode using the addDrawable method.
After starting the program, the text will appear:

Main application loop
Most graphics applications must constantly update the image on the screen: create and delete new objects, move them, change properties and render them frame by frame:

Scene changes are the operations that the application does. Until the application finishes its updates, it is impossible to start rendering the next frame - otherwise, in the process of traversing the tree with the rendering system, the graph may be in an inconsistent state, and the application will damage its memory or just fall. This means that the faster the updates are completed, the greater the FPS will be at the output.
When creating real-world applications, it makes sense to perform heavy computations simultaneously with the rendering phase in another stream. You can also create new objects of the scene. And when the main cycle reaches the scene change phase, it will be possible to quickly apply the results of calculations to the objects of the scene, link the created subtrees to the scene graph. Similarly, with the removal of a large number of objects. During the phase of changing the scene, you can simply link them from the tree and place them in the delete queue, and the actual destruction of the objects can be performed in another thread.
How to change the scene
For example, let's make the inscription "Hello, Habr" spinning on the screen. To do this, we first wrap the Geode in the MatrixTransform:
osg::MatrixTransform *mat = new osg::MatrixTransform; mat->addChild(geode); viewer.setSceneData(mat);
Then ask the Viewer to register our event handler:
RotationHandler *handler = new RotationHandler(mat); viewer.addEventHandler(handler);
Each event handler is an object that inherits the osgGA :: GUIEventHandler class. We are now interested in how to handle the FRAME event, which is called before each frame:
class RotationHandler: public osgGA::GUIEventHandler { public: RotationHandler(osg::MatrixTransform *mat): m_mat(mat) { } virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter &adapter) { osg::Matrix mat; switch (ea.getEventType()) { case osgGA::GUIEventAdapter::FRAME: mat.makeRotate(ea.getTime(), osg::Vec3(0.0f, 0.0f, 1.0f)); m_mat->setMatrix(mat); } } private: osg::ref_ptr<osg::MatrixTransform> m_mat; };
When you start the program, the text will begin to rotate around the axis (0, 0, 1).
What other features does OpenSceneGraph have?
We looked at the basic principles of scene construction, leaving behind the scenes a graph traversal, assigning attributes to nodes (materials, illumination), camera control, mouse and keyboard processing, and much more. Just to mention some interesting features:
- Visitor pattern implementation allows you to write your own class and ask OpenSceneGraph to bypass the graph, calling your code for each appropriate object of the scene;
- the Switch node (which is the successor of the Group) allows you to turn children on and off, excluding them from traversing the graph;
- The LOD node (also a successor of the Group) allows you to specify at what distance from the camera which of the children should be rendered. Allows to use more simple models at a great distance from the camera;
- shader support (fragment and geometry);
- To achieve high performance and scalability, there is support for multi-stream rendering of images from multiple cameras. Including multi-GPU;
- rendering to texture is possible;
- multi-layered textures, anisotropic lighting, bump-mapping, specular highlights;
- selection of scene objects into which the user points with the mouse (more precisely, the transformation of screen coordinates into a long and sharp polyhedron, which sticks to the screen, and then searches for intersections of this polyhedron with the scene objects and sorting the found objects by distance from the camera);
- many mathematical primitives for working with matrices, quaternions, polyhedra (calculating intersections, unions, etc.), 3d-morphing;
- Scene objects can be serialized and deserialized. New export and import formats are easily connected using the plugin system. The native format (osg) saves all attributes of objects in human-readable text format and allows you to accurately restore the graph after deserialization;
- special nodes of the HUD graph (head up display) allow children to be turned so that they are always facing the monitor;
Particle systems allow you to create various special effects such as fire, smoke, sparks, programming the frequency of creation of each particle, its trajectory, time of life, texture, etc .; - support for translucent objects and shadows;
- OpenThreads multithreading library allows you to abstract from the operating system and write a single code for all platforms;
- The osgDB module, in addition to simply loading and unloading objects onto a disk, has in its arsenal an object database module that allows them to be loaded in a background thread (paging mode);
- Integration with Qt allows you to render a GUI into a texture, which, in turn, can be stretched over some object of the scene. In particular, you can take a Qt-component of a web browser, place it on a texture, display it on the scene, open YouTube in the browser and watch some video. And it works;
- there is support for visualization of the earth's surface (terrain) and sky (skybox);
- the ability to work on mobile platforms Android and iOS;
- Excellent license (relaxed LGPL), allowing even statically linking the library with closed projects.
Where to get
Official site -
www.openscenegraph.orgThe best documentation -
books from authors .
The best documentation available for free is a huge number of examples supplied with the library, and a great code that is easy and pleasant to read.