
Introduction
As a rule, working with rendering parameters, OpenGL acts as a state machine. A rendering state is a collection of state attributes, such as light sources, materials, textures, and display modes, turned on and off with glEnable () and glDisable (). When you set a specific state, it is valid until some other function changes it. The OpenGL pipeline supports a state stack to save and restore states at any time. The state machine gives the developer complete control over the current rendering states and those stored on the stack.
However, this approach is inconvenient when working with OSG. For this reason, the OpenGL state machine is encapsulated by the osg :: StateSet class, which takes over the operations of working with the state stack and setting it while traversing the scene graph.
An instance of the osg :: StateSet class contains a subset of various rendering states and can apply them to the osg :: Node scene nodes and the osg :: Drawable geometric objects using the setStateSet () method
osg::StateSet *stateset = new osg::StateSet; node->setStateSet(stateset);
A safer way would be to use the getOrCreateStateSet () method, which ensures that the correct state is returned and attached to the node or drawable object.
')
osg::StateSet *stateset = node->getOrCreateStateSet();
The classes osg :: Node and osg :: Drawable control the osg :: StateSet member variable via the smart pointer osg :: ref_ptr <>. This means that a set of states can be divided between several objects of the scene and will be destroyed only when all of these objects are destroyed.
1. Attributes and modes
OSG defines the osg :: StateAttribute class for storing rendering attributes. This is a virtual base class that is inherited by various rendering attributes, such as light, material, and fog.
Rendering modes work like switches that can be turned on and off. In addition, they are associated with enumerators, which are used to specify the type of OpenGL mode. Sometimes rendering mode is associated with an attribute, for example, GL_LIGHTING mode includes variables for light sources that are sent to the OpenGL pipeline when turned on, and turns off lights otherwise.
The osg :: StateSet class divides attributes and modes into two groups: texture and non-texture. It has several public methods for adding non-textural attributes and modes to a set of states:
- setAttribute () - adds an object of type osg :: StateAttribute to the set of states. Attributes of the same type cannot coexist in the same set of states. The previous set point will be overwritten by a new one.
- setMode () - attaches a mode enumerator to a set of states and sets its value to osg :: StateAttribute :: ON or osg :: StateAttribute :: OFF, which means enable or disable the mode.
- setAttributeAndModes () - attaches the rendering attribute and its associated mode and sets the value of the switch (the default is ON). It should be borne in mind that not every attribute has a corresponding mode, but you can use this method anyway.
To set the attribute and its associated mode, you can use this code.
stateset->setAttributeAndModes(attr, osg::StateAttribute::ON);
To set texture attributes, you must pass an additional parameter to specify the texture to which it should be applied. For this, osg :: StateSet provides several other public methods, such as setTextureAttribute (), setTextureMode () and setTextureAttributeAndModes ()
stateset->setTextureAttributeAndModes(0, textattr, osg::StateAttribute::ON);
applies the textattr attribute to the texture with id 0.
2. Setting polygon display mode for scene nodes
We illustrate the above theory with a practical example — changing the rasterization mode of OpenGL polygons using the class osg :: PolygonMode, which inherits from osg :: StateAttribute. This class encapsulates the glPolygonMode () function and provides an interface for setting the display mode of polygons for a particular scene node.
Polygonmode examplemain.h #ifndef MAIN_H #define MAIN_H #include <osg/PolygonMode> #include <osg/MatrixTransform> #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::Node> model = osgDB::readNodeFile("../data/cessna.osg"); osg::ref_ptr<osg::MatrixTransform> transform1 = new osg::MatrixTransform; transform1->setMatrix(osg::Matrix::translate(-25.0f, 0.0f, 0.0f)); transform1->addChild(model.get()); osg::ref_ptr<osg::MatrixTransform> transform2 = new osg::MatrixTransform; transform2->setMatrix(osg::Matrix::translate(25.0f, 0.0f, 0.0f)); transform2->addChild(model.get()); osg::ref_ptr<osg::PolygonMode> pm = new osg::PolygonMode; pm->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE); transform1->getOrCreateStateSet()->setAttribute(pm.get()); osg::ref_ptr<osg::Group> root = new osg::Group; root->addChild(transform1.get()); root->addChild(transform2.get()); osgViewer::Viewer viewer; viewer.setSceneData(root.get()); return viewer.run(); }
Here we will load the model of our beloved Cessna and applying transformations to it we will receive two instances of the model. To one of them, the fact that on the left, we apply an attribute that sets the frame display mode of polygons
osg::ref_ptr<osg::PolygonMode> pm = new osg::PolygonMode; pm->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE); transform1->getOrCreateStateSet()->setAttribute(pm.get());

If you refer to the OpenGL specification, you can easily imagine what polygon display options will be available to us when using setMode () in this particular case. The first parameter can take the values osg :: PolygonMode :: FRONT, BACK and FRONT_AND_BACK, corresponding to the OpenGL enumerators GL_FRONT, GL_BACK, GL_FRONT_AND_BACK. The second parameter can be osg :: PolygonMode :: POINT, LINE and FILL, which correspond to GL_POINT, GL_LINE and GL_FILL. No other tricks, as is often the case when developing on pure OpenGL, are not needed here - OSG takes over most of the work. The polygon display mode has no associated mode and does not require calling the glEnable () / glDisable () pair. The setAttributeAndModes () method will work fine in this case, but the value of its third parameter will be useless.
3. Inheritance of rendering states. Apply Attributes and Modes
The set of node states affects the current node and all its children. For example, the attribute osg :: PolygonMode set for the transform1 node from the previous example will be applied to all children of this node. However, the child node can override the parent attributes, that is, the rendering state will inherit from the parent node if the child node does not change the behavior.
Sometimes it is required to redefine the behavior of the node in the application of attributes. For example, in most 3D editors, a user can load several models and change their display mode for all loaded models at the same time, regardless of how they were previously displayed. In other words, all models in the editor must inherit a single attribute, regardless of how it was previously set for each of the models. In OSG, this can be implemented using the osg :: StateAttribute :: OVERRIDE flag, for example
stateset->StateAttribute(attr, osg::StateAttribute::OVERRIDE);
When setting modes and modes with attributes, the operator is used bitwise OR
stateset->StateAttributeAndModes(attr, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
In addition, it is possible to protect an attribute from overriding - for this, it must be flagged with the osg :: StateAttribute :: PROTECTED flag.
There is a third flag, osg :: StateAttribute :: INHERIT, which is used to indicate that this attribute should be inherited from the set of states of the parent node.
Here is a brief example of using the OVERRIDE and PROTECTED flags. The root node will be set to OVERRIDE to force all the child nodes to inherit its attributes and modes. In this case, the child nodes will try to change their state with or without the help of the PROTECTED flag, which will lead to different results.
Inherit example textmain.h #ifndef MAIN_H #define MAIN_H #include <osg/PolygonMode> #include <osg/MatrixTransform> #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::Node> model = osgDB::readNodeFile("../data/glider.osg"); osg::ref_ptr<osg::MatrixTransform> transform1 = new osg::MatrixTransform; transform1->setMatrix(osg::Matrix::translate(-0.5f, 0.0f, 0.0f)); transform1->addChild(model.get()); osg::ref_ptr<osg::MatrixTransform> transform2 = new osg::MatrixTransform; transform2->setMatrix(osg::Matrix::translate(0.5f, 0.0f, 0.0f)); transform2->addChild(model.get()); osg::ref_ptr<osg::Group> root = new osg::Group; root->addChild(transform1.get()); root->addChild(transform2.get()); transform1->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); transform2->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED); root->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); osgViewer::Viewer viewer; viewer.setSceneData(root.get()); return viewer.run(); }

To understand what is going on in general, you need to see how a normally-lit glider looks like by downloading its OSG osgviewer
$ osgviewer glider.osg
In the example we are trying to change the lighting mode for the transform1 and transform2 nodes, turning off the lighting completely.
transform1->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); transform2->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
At the same time, we enable the lighting mode for the root node, and using the OVERRIDE flag for all its child nodes, so that they inherit the status of the root node. However, trnsform2 uses the PROTECTED flag to prevent the influence of root node settings.
transform2->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
As a result, despite the fact that we turn off the lighting at the transform1 node, the left hang-glider is still lit, as the settings of the scene root blocked our attempt to turn off the lighting for it. The right hang glider is displayed without illumination (it looks brighter only because it is filled with a simple color without calculating the illumination), since transform2 is protected from inheriting the attributes of the root node.
4. List of OpenGL attributes supported in OpenSceneGraph
OSG supports almost all the attributes and rendering modes supported by OpenGL, through classes derived from osg :: StateAttribute. The table shows all the parameters of the machine state OpenGL, available from the engine.
Attribute type id | Class name | Associated mode | Equivalent opengl function |
---|
ALPHEFUNC | osg :: AlphaFunc | GL_ALPHA_TEST | glAlphaFunc () |
BLENDFUNC | osg :: BlendFunc | GL_BLEND | glBlendFunc () and glBlendFuncSeparate () |
CLIPPLANE | osg :: ClipPlane | GL_CLIP_PLANEi (i from 1 to 5) | glClipPlane () |
COLORMASK | osg :: ColorMask | - | glColorMask () |
Cullface | osg :: CullFace | GL_CULLFACE | glCullFace () |
DEPTH | osg :: Depth | GL_DEPTH_TEST | glDepthFunc (), glDepthRange () and glDepthMask () |
FOG | osg :: Fog | GL_FOG | glFog () |
FRONTFACE | osg :: FrontFace | - | glFrontFace () |
LIGHT | osg :: Light | GL_LIGHTi (i from 1 to 7) | glLight () |
LIGHTMODEL | osg :: LightModel | - | glLightModel () |
LINESTRIPPLE | osg :: LineStripple | GL_LINE_STRIPPLE | glLineStripple () |
LINEWIDTH | osg :: LineWidth | - | glLineWidht () |
LOGICOP | osg :: LogicOp | GL_COLOR_LOGIC_OP | glLogicOp () |
MATERIAL | osg :: Material | - | glMaterial () and glColorMaterial () |
POINT | osg :: Point | GL_POINT_SMOOTH | glPointParameter () |
POINTSPRITE | osg :: PointSprite | GL_POINT_SPRITE_ARB | Functions for working with OpenGL sprites |
POLYGONMODE | osg :: PolygonMode | - | glPolygonMode () |
POLYGONOFFSET | osg :: PolygonOffset | GL_POLYGON_OFFSET_POINT | glPolygonOffset () |
POLYGONSTRIPPLE | osg :: PolygonStripple | GL_POLYGON_STRIPPLE | glPolygonStripple () |
Scissor | osg :: Scissor | GL_SCISSOR_TEST | glScissor () |
SHADEMODEL | osg :: ShadeModel | - | glShadeModel () |
STENCIL | osg :: Stencil | GL_STENCIL_TEST | glStencilFunc (), glStencilOp () and glStencilMask () |
TEXENV | osg :: TexEnv | - | glTexEnv () |
TEXGEN | osg :: TexGen | GL_TEXTURE_GEN_S | glTexGen () |
The attribute type ID column refers to the specific OSG identifier, which denotes this attribute in the enumerators of the osg :: StateAttribute class. It can be used in the getAttribute method to get the value of a specific attribute.
osg::PolygonMode *pm = dynamic_cast<osg::PolygonMode *>(stateset->getAttribute(osg::StateAttribute::POLYGONMODE));
Valid pointer indicates that the attribute was set earlier. Otherwise, the Wrenet method is NULL. You can also get the value of the current mode by using the call
osg::StateAttribute::GLModeValue value = stateset->getMode(GL_LIGHTING);
Here the GL_LIGHTING enumerator is used to turn on / off the lighting for the entire scene.
5. Applying fog to the model in the scene
Let us take as an example the fog effect as an ideal way to show techniques for working with various attributes and rendering modes. OpenGL uses one linear and two exponential equations describing the fog model, supported by the class osg :: Fog.
Example text fogmain.h #ifndef MAIN_H #define MAIN_H #include <osg/Fog> #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::Fog> fog = new osg::Fog; fog->setMode(osg::Fog::LINEAR); fog->setStart(500.0f); fog->setEnd(2500.0f); fog->setColor(osg::Vec4(1.0f, 1.0f, 0.0f, 1.0f)); osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("../data/lz.osg"); model->getOrCreateStateSet()->setAttributeAndModes(fog.get()); osgViewer::Viewer viewer; viewer.setSceneData(model.get()); return viewer.run(); }
First we create the fog attribute. We use a linear model, adjust the range of the display of fog in range to the model
osg::ref_ptr<osg::Fog> fog = new osg::Fog; fog->setMode(osg::Fog::LINEAR); fog->setStart(500.0f); fog->setEnd(2500.0f); fog->setColor(osg::Vec4(1.0f, 1.0f, 0.0f, 1.0f));
We load a sample of the landscape lz.osg and apply this attribute to it.
osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("../data/lz.osg"); model->getOrCreateStateSet()->setAttributeAndModes(fog.get());
In the viewer window we see a blurred landscape, and we can see how the fog density varies depending on the distance to the model.



6. Work with light sources and lighting
As in OpenGL, OSG supports up to eight light sources for direct meeting of scene objects. Like OpenGL, OSG does not automatically calculate shadows. Light rays come from sources in straight lines, are reflected from objects and scattered by them, and then perceived by the eyes of the viewer. For high-quality lighting processing, it is necessary to set the properties of the material, the normals of the geometry of objects, etc.
The osg :: Light class provides methods for controlling light sources, including: setLightNum () and getLightNum () for working with the number of sources; setAmbient () and getAmbient () to control the surrounding component; setDiffuse () and getDiffuse () - for working with a scattered component, etc.
In addition, OSG describes the osg :: LightSource class for adding light sources to the scene. It provides the setLight () method and is a leaf node of a scene graph with a single attribute. All other nodes of the scene graph are affected by the light source if the appropriate mode for GL_LIGHTi is set. For example:
Another more convenient solution is the setStateSetModes () method, by which the light with the required number is automatically attached to the root node.
root->addChild( lightSource.get() ); lightSource->setStateSetModes( root->getOrCreateStateSet(), osg::StateAttribute::ON );
You can add child nodes to the light source, but this does not mean at all, you will light the subgraph connected with it somehow in a special way. It will be processed as a geometry, represented by the physical form of the light source.
The osg :: LightSource node can be attached to a transformation node, for example, a point light source can be moved in space. This can be disabled by setting the absolute coordinate system for the light source.
lightSource->setReferenceFrame( osg::LightSource::ABSOLUTE_RF );
7. Creating lights in the scene
By default, OSG automatically adjusts the light source number 0, which emits a uniform directional light to the scene. However, at any time you can add several additional light sources, and even manage them by applying the coordinate transformation nodes. Only positional sources (point sources) can be moved. Directional light has only a direction (a stream of parallel rays coming from infinity) and is not tied to a specific position on the stage. OpenGL and OSG use the fourth component of the position parameter to specify the type of light source. If it is 0, then the light is treated as directed; with a value of 1 - positional.
Consider a small example of working with lighting.
Spoiler headermain.h #ifndef MAIN_H #define MAIN_H #include <osg/MatrixTransform> #include <osg/LightSource> #include <osgDB/ReadFile> #include <osgViewer/Viewer> #endif
main.cpp #include "main.h"
Let's create a separate function to create a light source.
osg::Node *createLightSource(int num, const osg::Vec3 &trans, const osg::Vec4 &color) { osg::ref_ptr<osg::Light> light = new osg::Light; light->setLightNum(num); light->setDiffuse(color); light->setPosition(osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); osg::ref_ptr<osg::LightSource> lightSource = new osg::LightSource; lightSource->setLight(light); osg::ref_ptr<osg::MatrixTransform> sourceTrans = new osg::MatrixTransform; sourceTrans->setMatrix(osg::Matrix::translate(trans)); sourceTrans->addChild(lightSource.get()); return sourceTrans.release(); }
In this function, we first define the lighting parameters given by the source, thereby creating the attribute GL_LIGHTi
osg::ref_ptr<osg::Light> light = new osg::Light;
After that a light source is created, which is assigned this attribute.
osg::ref_ptr<osg::LightSource> lightSource = new osg::LightSource; lightSource->setLight(light);
Create and set up a transformation node, passing our light source to it as a child node
osg::ref_ptr<osg::MatrixTransform> sourceTrans = new osg::MatrixTransform; sourceTrans->setMatrix(osg::Matrix::translate(trans)); sourceTrans->addChild(lightSource.get());
Return a pointer to the transformation node
return sourceTrans.release();
In the body of the main program, we load a three-dimensional model (again, our favorite Cessna)
osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("../data/cessna.osg"); osg::ref_ptr<osg::Group> root = new osg::Group; root->addChild(model.get());
Create two light sources with numbers 0 and 1. The first will shine yellow, the second - blue-green
osg::Node *light0 = createLightSource(0, osg::Vec3(-20.0f, 0.0f, 0.0f), osg::Vec4(1.0f, 1.0f, 0.0f, 1.0f)); osg::Node *light1 = createLightSource(1, osg::Vec3(0.0f, -20.0f, 0.0f), osg::Vec4(0.0f, 1.0f, 1.0f, 1.0f));
We inform the state machine OpenGL that it is necessary to include 0 and 1 light sources and add the sources we created to the scene.
root->getOrCreateStateSet()->setMode(GL_LIGHT0, osg::StateAttribute::ON); root->getOrCreateStateSet()->setMode(GL_LIGHT1, osg::StateAttribute::ON); root->addChild(light0); root->addChild(light1);
After initialization and launch of the viewer, we get a picture

Conclusion
Very touched by the attention of interested people to this cycle. This action did not start very much, but I feel that the articles are needed by the community. Thank you for all the positive feedback.
Today I tried to consider, again, the rather basic things of the OSG engine. Not sure what happened cool. But for now I am setting forth precisely primitive things, in the vein in which I understood them myself. I checked all the examples personally, my repository is available
here . Thank you, dear colleagues, I will try so that this story has a
sequel ...