Библиотека OpenGL, на базе которой построен OpenSceneGraph, использует геометрические примитивы (такие как точки, линии, треугольники и полигональные грани) для построения всех объектов трехмерного мира.

Эти примитивы задаются данными об их вершинах, в которые входят координаты вершин, компоненты нормалей, данные о цвете и текстурные координаты. Эти данные могут хранится в специальных массивах. Примитивы могут быть сформированы путем разыменования и индексирования элементов массива. Этот метод называется методом массива вершин, он позволяет исключить хранение в памяти избыточных вершин и обладает хорошим быстродействием.

Кроме того, OpenGL может использовать механизм так называемых дисплейных списков, когда однажды подготовленные в видеопамяти примитивы могут использоваться повторно, что существенно ускоряет отображение статических объектов.

По-умолчанию OSG использует метод массивов вершин и метод дисплейных списков для рендеринга геометрии. Однако, стратегия рендеринга может быть изменена, в зависимости от того, каким образом представлены данные о геометрии.

Классы Geode и Drawable

Класс osg::Geode представляет собой оконечный, так называемый “листовой” узел дерева сцены. Он не может иметь дочерних узлов, но при этом содержит всю необходмую информацию для рендеринга геометрии. Его имя - Geode есть сокращение от слов geometry node.

Геометрические данные, подлежащие обработке движком запоминаются в наборе объектов класса osg::Drawable, управляемых классом osg::Geode. Класс osg::Drawable не инстанцируется и является чисто виртуальным классом. От него наследуются ряд подклассов, представляющих собой трехмерные модели, изображения и текст, обрабатываемые конвейером OpenGL. Под drawable в OSG понимаются все элементы, которые могут быть отрендерены движком.

Класс osg::Geode предоставляет ряд методов для присоединения и отсоединения drawables:

  • Публичный метод addDrawable() - передает указатель на drawable элемент в экземпляр класса osg::Geode. Все эти элементы управляются посредством умных указателей osg::ref_ptr<>.
  • Публичный метод removeDrawable() и removeDrawables() удаляет объект из osg::Geode и уменьшает счетчик ссылок на него. Метод removeDrawable() принимает в качестве единственного параметра указатель на интересующий элемент, а метод removeDrawables() принимает два параметра: начальный индекс и число элементов, подлежащих удалению из массива объектов osg::Geode.
  • Метод getDrawable() возвращает указатель на элемент по передаваемому в качестве параметра индексу.
  • Метод getNumDrawables() возвращает общее число элементов, прикрепленных к osg::Geode. Например, для удаления всех элементов из osg::Geode можно использовать такой код
geode->removeDrawables(0, geode->getNumDrawables());

Рендеринг простейших фигур

OSG предоставляет класс osg::ShapeDrawable, являющийся наследником класса osg::Drawable, и предназначенный для создания простейших трехмерных примитивов. Этот класс включает в себя объект osg::Shape, хранящий информацию о спецефической геометрии и ещё параметрах. Генерация примитивов осуществляется с помощью метода setShape(), например

shapeDrawable->setShape(new osg::Box(osg::Vec3(1.0f, 0.0f, 0.0f), 10.0f, 10.0f, 5.0f));

создает прямоугольный параллелепипед с геометрическим центром в точке (1.0, 0.0, 0.0) c шириной и высотой 10 и глубиной 5 единиц. Класс osg::Vec3 определяет вектор в трехмерном пространстве (кроме того, представлены и классы osg::Vec2 и osg::Vec4 описывающие векторы соответствующей размерности).

Наиболее популярные примитивы представлены в OSG классами osg::Box, osg::Capsule, osg::Cone, osg::Cylinder и osg::Sphere.

Рассмотрим пример применения данного механизма.

main.h

#ifndef     MAIN_H
#define     MAIN_H

#include    <osg/ShapeDrawable>
#include    <osg/Geode>
#include    <osgViewer/Viewer>

#endif // MAIN_H

main.cpp

#include    "main.h"

int main(int argc, char *argv[])
{
    (void) argc;
    (void) argv;

    osg::ref_ptr<osg::ShapeDrawable> shape1 = new osg::ShapeDrawable;
    shape1->setShape(new osg::Box(osg::Vec3(-3.0f, 0.0f, 0.0f), 2.0f, 2.0f, 1.0f));

    osg::ref_ptr<osg::ShapeDrawable> shape2 = new osg::ShapeDrawable;
    shape2->setShape(new osg::Cone(osg::Vec3(0.0f, 0.0f, 0.0f), 1.0f, 1.0f));
    shape2->setColor(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f));

    osg::ref_ptr<osg::ShapeDrawable> shape3 = new osg::ShapeDrawable;
    shape3->setShape(new osg::Sphere(osg::Vec3(3.0f, 0.0f, 0.0f), 1.0f));
    shape3->setColor(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f));

    osg::ref_ptr<osg::Geode> root = new osg::Geode;

    root->addDrawable(shape1.get());
    root->addDrawable(shape2.get());
    root->addDrawable(shape3.get());

    osgViewer::Viewer viewer;
    viewer.setSceneData(root.get());

    return viewer.run();
}

Данный пример особенно не нуждается в комментариях: в программе создаются три простейшие фигуры, после компиляции и запуска мы увидим такой результат

Механизм, приведенный в примере прост и понятен, однако не является самым эффективным способом создания геометрии и может использоваться исключительно для тестов. Для создания геометрии в высокопроизводительных приложениях на базе OSG используется класс osg::Geometry.