Знакомство с графическим движком OpenSceneGraph начнем с простейшего примера, как это обычно принято в программировании с некоего “Hello world!”.

Прежде чем писать какой-либо код, кастроим наш проект для системы сборки qmake, которую мы будем использовать на протяжении всего цикла статей. В интересующем нас месте файловой системы создадим следующию структуру каталогов

OSG-lessons/
	|-data/
	|-OSG-lessons/
		|
		|-hello/
			|-include/
			|-src/

В каталоге hello создадим файл hello.pro следующего содержания

TEMPLATE = app

TARGET = hello

DESTDIR = ../../bin

win32 {

    OSG_LIB_DIRECTORY = $$(OSG_BIN_PATH)
    OSG_INCLUDE_DIRECTORY = $$(OSG_INCLUDE_PATH)


    CONFIG(debug, debug|release) {

        TARGET = $$join(TARGET,,,_d)

        LIBS += -L$$OSG_LIB_DIRECTORY -losgd
        LIBS += -L$$OSG_LIB_DIRECTORY -losgViewerd
        LIBS += -L$$OSG_LIB_DIRECTORY -losgDBd
        LIBS += -L$$OSG_LIB_DIRECTORY -lOpenThreadsd

    } else {

        LIBS += -L$$OSG_LIB_DIRECTORY -losg
        LIBS += -L$$OSG_LIB_DIRECTORY -losgViewer
        LIBS += -L$$OSG_LIB_DIRECTORY -losgDB
        LIBS += -L$$OSG_LIB_DIRECTORY -lOpenThreads

    }

    INCLUDEPATH += $$OSG_INCLUDE_DIRECTORY
}

unix {

    CONFIG(debug, debug|release) {

        TARGET = $$join(TARGET,,,_d)

        LIBS += -losgd
        LIBS += -losgViewerd
        LIBS += -losgDBd
        LIBS += -lOpenThreadsd

    } else {

        LIBS +=  -losg
        LIBS +=  -losgViewer
        LIBS +=  -losgDB
        LIBS +=  -lOpenThreads

    }
}

INCLUDEPATH += ./include

HEADERS += $$files(./include/*.h)
SOURCES += $$files(./src/*.cpp)

Разберем эти письме подробнее

TEMPLATE = app
TARGET = hello
DESTDIR = ../../bin

Переменные задают шаблон проекта (app - приложение), имя исполняемого файла (hello) и каталог, куда исполняемый файл помещается после сборки.

win32 {

    OSG_LIB_DIRECTORY = $$(OSG_BIN_PATH)
    OSG_INCLUDE_DIRECTORY = $$(OSG_INCLUDE_PATH)


    CONFIG(debug, debug|release) {

        TARGET = $$join(TARGET,,,_d)

        LIBS += -L$$OSG_LIB_DIRECTORY -losgd
        LIBS += -L$$OSG_LIB_DIRECTORY -losgViewerd
        LIBS += -L$$OSG_LIB_DIRECTORY -losgDBd
        LIBS += -L$$OSG_LIB_DIRECTORY -lOpenThreadsd

    } else {

        LIBS += -L$$OSG_LIB_DIRECTORY -losg
        LIBS += -L$$OSG_LIB_DIRECTORY -losgViewer
        LIBS += -L$$OSG_LIB_DIRECTORY -losgDB
        LIBS += -L$$OSG_LIB_DIRECTORY -lOpenThreads

    }

    INCLUDEPATH += $$OSG_INCLUDE_DIRECTORY
}

В зависимости от ОС, где собирается проект, определяем переменные, указывающие пути к каталогам библиотек и заголовочных файлов OSG. Вот тут-то нам и пригодились переменные окружения OSG_BIN_PATH и OSG_INCLUDE_PATH - теперь неважно, где установлена библиотека OSG. Любой желающий работать с этим проектом на своем компьютере просто пропишет соотвествующие переменные окружения в своей системе, не редактируя сценарий сборки.

CONFIG(debug, debug|release) {

    TARGET = $$join(TARGET,,,_d)

    LIBS += -L$$OSG_LIB_DIRECTORY -losgd
    LIBS += -L$$OSG_LIB_DIRECTORY -losgViewerd
    LIBS += -L$$OSG_LIB_DIRECTORY -losgDBd
    LIBS += -L$$OSG_LIB_DIRECTORY -lOpenThreadsd

} else {

    LIBS += -L$$OSG_LIB_DIRECTORY -losg
    LIBS += -L$$OSG_LIB_DIRECTORY -losgViewer
    LIBS += -L$$OSG_LIB_DIRECTORY -losgDB
    LIBS += -L$$OSG_LIB_DIRECTORY -lOpenThreads

}

Пишем сценарий для сборки в unix-подобных ОС

unix {

    CONFIG(debug, debug|release) {

        TARGET = $$join(TARGET,,,_d)

        LIBS += -losgd
        LIBS += -losgViewerd
        LIBS += -losgDBd
        LIBS += -lOpenThreadsd

    } else {

        LIBS +=  -losg
        LIBS +=  -losgViewer
        LIBS +=  -losgDB
        LIBS +=  -lOpenThreads

    }
}

Здесь мы настраиваем имя исполняемого файла и указываем библиотеки, которые следует компоновать с нашей программой для различных вариантов сборки: как отладочной так и релизной. Отладочные библиотеки OSG имеют суффикс “d” после имени файла. Суффикс “_d” мы добавим так же и к исполняемому файлу проекта, дабы отличать отладочный вариант от релизного.

INCLUDEPATH += $$OSG_INCLUDE_DIRECTORY

INCLUDEPATH += ./include

HEADERS += $$files(./include/*.h)
SOURCES += $$files(./src/*.cpp)

Ну и наконец определяем пути поиска заголовочных файлов и файлы, включаемые в дерево проекта. Создаем в каталоге include/ пустой файл main.h, а в кталоге src/ - файл main.cpp. Открываем этот проект в QtCreator и настраиваем его так, как показано на скриншоте

После открытия проекта увидим следующую картину

Напишем такой код в файле main.h

#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::ref_ptr<osg::Node> root = osgDB::readNodeFile("../data/cessna.osg");
    osgViewer::Viewer viewer;
    viewer.setSceneData(root.get());

    return viewer.run();
}

Файл с моделькой самолета необходимо скопировать в каталог data/. Этот файл, а так же многое из того, что будет использовано в данном цикле статей, можно скачать из репозитория OpenSceneGraph-Data

После компиляции и запуска мы получим что-то вроде этого

Первые две строчки нашего кода

	(void) argc;
	(void) argv;

помечают входные параметры функции main() как неиспользуемые, дабы избежать предупреждения компилятора. Далее создается корневая нода сцены, в качестве которой выступает модель самолета, загружаемая из файла cessna.osg

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

Потом создается экземпляр класса osgViewer::Viewer - так называемый “вьювер” - объект управляющий отображением сцены на экране. Вьюверу передаются данные сцены

	viewer.setSceneData(root.get());

и запускается цикл отрисовки сцены

	return viewer.run();

В этом простейшем коде уже содержится ряд базовых концепций, используемых в OSG. Но разговор о них пойдет чуть попозже.