Понедельник, 25 Ноября 2024, 03:55

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 1
  • 1
G3D Engine
pekarДата: Понедельник, 21 Июня 2010, 12:30 | Сообщение # 1
почетный гость
Сейчас нет на сайте
Прошу в этой теме выкладывать все что нашли по этому движку и все кто с ним работает планируется создание русского компьюнити но инфы мала прошу людей откликнутся или связатся по аське 550632194

Добавлено (21.06.2010, 12:30)
---------------------------------------------
Взято с WIKI
На данной странице я попытаюсь систематизировать свои познания о G3D на русском языке. По возможности, я постараюсь писать развернуто. Т.е. не сухой перевод документации по всем классам, их методам и переменным, а как можно более подробно... с объяснениями и примерами.

Если не указано обратного, то все классы находятся в пространстве имен G3D, т.е. нет необходимости каждый раз указывать"using namespace G3D". Вся документация относится к движку версии 8.00 BETA 4 (на момент написания этих строк).

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

G3D имеет встроенный сборщик мусора, который для управления памятью, использует подсчет количества указателей на объект. Большинство классов G3D управляются сборщиком мусора. Для того чтобы создать объект, который будет автоматически управлять памятью, необходимо объявить класс с окончанием "Ref" в конце имени класса или же использовать собственный производный класс от родительского. Общий вид объявления выглядит так:

Code
typedef G3D::ReferenceCountedPointer<Foo> FooRef;
, где Foo - имя класса.

Ниже показан пример создания указателя на объект, хранящий изображение:
Code
Texture::Ref map_texture = G3D::Texture::fromFile("apple.jpg");

Как видите, память для таких объектов выделяется специальными методами вместо использования new(), malloc(), а указатель на объект хранится в Ref (G3D::Texture::Ref вместо G3D::Texture*). В примере выше метод G3D::Texture::fromFile создает объект типа Texture::Ref. Класс Texture::Ref это класс Texture, унаследованный от ReferenceCountedPointer. В дальнейшем вы можете использовать Ref как самый обычный указатель, доступ к членам осуществляется при помощи -> (стрелка).

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

Запомните! Если класс имеет наследника Ref, вы никогда не должны использовать непосредственно родительский класс, используйте Ref. Ну и естественно, что вы не должны вручную очищать выделенную для них память при помощи free() или delete. G3D возьмет эту заботу на себя. В закреплении выше сказанного предлагаю разобрать следующий пример:

Code
1  class Foo : public G3D::ReferenceCountedObject {
2  public:
3    int x;
4  };
5       
6  class Bar : public Foo {};      
7  typedef G3D::ReferenceCountedPointer<Foo> FooRef;
8  typedef G3D::WeakReferenceCountedPointer<Foo> WeakFooRef;
9  typedef G3D::ReferenceCountedPointer<Bar> BarRef;
10       
11 int main(int argc, char *argv[]) {
12    WeakFooRef x;
13    {
14       FooRef a = new Foo();   //количество ссылок на класс FooRef равно 1
15       x = a;                  //объект типа weak не увеличивает значение счетчика (тип данных не совпадает)
16       {
17          FooRef b = a;        //количество ссылок на класс FooRef теперь равно 2
18       }                       //количество ссылок на класс FooRef снова равно 1 (объект "b" уничтожился по достижению конца блока)
19    }                          //А теперь и объект "a" уничтожился, количество ссылок равно 0
20      
21    return 0;      
22 }

Пример довольно примитивный, но позволяет понять логику работы. Разберем подробно что в нем происходит.

Создается класс Foo, наследующий открытые методы класс ReferenceCountedObject. Теперь, если создать объект типа ReferenceCountedPointer<Foo> (в ReferenceCountedPointer<> можно включать только те классы, которые наследуются от ReferenceCountedObject), то такой объект перейдет под управление сборщика мусора, т.е. станет "garbage collected". Согласитесь, немного неудобно каждый раз писать такой длинный идентификатор, именно поэтому 7-9 строки определяют пользовательское имя (псевдоним) для этого определения.

Вы обратили внимание, что в этом примере ни разу не вызывается метод delete() для освобождения памяти? Если бы класс Foo не наследовал ReferenceCountedObject, то в строке 19 память бы автоматически не очищалась. Т.е. уничтожиться то объект - уничтожился бы, но выделенная для его хранения память так и осталась бы занятой. А представь что будет если активно создаются и уничтожаются тысячи объектов. Свободная оперативка быстро закончится. Но поскольку Foo наследует ReferenceCountedObject, нам не нужно беспокоится о том, что мы забыли освободить память, когда объект стал более не нужен. В строке 19 это происходит автоматически. Contents [hide]
1 класс GApp
2 класс RenderDevice
3 класс Film
4 класс Material
5 класс ArticulatedModel
6 класс ArticulatedModel::Preproccess
7 класс BumpMap
8 класс SuperShader
9 класс _BSPMap::Map

класс GApp

Этот класс является каркасом (анг. framework), который управляет всеми событиями, происходящими в G3D и связывает все компоненты воедино. Его основные задачи:
Рендеринг кадров
Реакция на нажатие клавиш
Логика (предусмотрен специальный метод)
Физика (метод, вызывающий методы из физического движка)

У данного класса очень много методов, дружественных функций и параметров. Опишу основные из них

GApp::GApp(const Settings &options = Settings(), OSWindow *window = NULL)

Конструктор. По традиции в C++, конструктор используется для инициализации объекта. Так и здесь GApp() подготавливает приложение к запуску. Конструктор создает объект RenderDevice, UserInput, GConsole, FirstPersonManipulator и т.д. Обо всех этих классах я расскажу чуть позже, сейчас лишь стоит вкратце упомянуть что за что отвечает.

Итак, RenderDevice - это класс, через который происходит непосредственное взаимодействие с графическим чипсетом. Ну и соответственно с функциями OpenGL.

UserInput - класс, через методы которого обрабатывается пользовательский ввод.

GConsole - консоль для ввода команд. Тут стоит отметить, что поскольку объект типа GConsole создается в конструкторе, ему присваивается идентификатор console, то в принципе нет необходимости создавать свой собственный экземпляр... разве что вы захотите переопределить ее методы с помощью виртуальных функций.

FirstPersonManipulator - класс, отвечающий за работу мыши, джойстика, клавиатуры и т.д. В конструкторе создается объект этого класса с именем defaultController. В дальнейшем этот объект используется для управления положением камеры и направлением ее взгляда.

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

Если посмотреть заголовочный файл GApp.h (G3D/GLG3D.lib/include/GLG3D/GApp.h), то вы увидите, что внутри класса GApp создаются еще два класса:

- GApp::Settings;

- GApp::DebugShape.

А внутри GApp::Settings создается класс GApp::Settings::FilmSettings.

Класс Settings служит для настройки приложения во время инициализации (разрешение экрана в пикселях, использовать ли полноэкранный режим, создавать ли файл с лицензией и т.д.). Так же внутри этого класса объявляется класс FilmSettings, а затем создается объект этого класса с именем film. Через методы этого класса осуществляется работа с буффером кадров (FrameBuffer).

После того как все параметры приложения заданы, можно передавать их в конструктор.

Пример:

Code

//Объявляем класс App, который наследует класс GApp
class App : public GApp {
private:
         ...
         void message(const std::string& msg) const;
         void renderSplash();
         ...
public:
         //Переопределяем родительские методы на свои собственные
         App(const GApp::Settings& settings = GApp::Settings());
         virtual void onUserInput(UserInput* ui);
         virtual void onSimulation(RealTime rdt, SimTime sdt, SimTime idt);
         virtual void onPose(Array<Surface::Ref>& posed3D, Array<Surface2D::Ref>& posed2D);
         virtual void onGraphics2D(RenderDevice* rd, Array<Surface2D::Ref>& posed2D);
         virtual void onGraphics3D(RenderDevice* rd, Array<Surface::Ref>& posed3D);
};

int main(int argc, char* argv[])
{
         GApp::Settings settings; //Здесь будут определяться параметры, которые затем будут переданы
                        //в конструктор App() для инициализации

         settings.film.enabled = true; //Используем FrameBuffer
         settings.window.caption = "LOKI"; //Заголовок окна
         settings.window.width = 800; //Разрешение по горизонтали
         settings.window.height = 600; //Разрешение по вертикали
         settings.window.fullScreen = false; //Не используем полноэкранный режим
         settings.window.framed = false; //Отключаем заголовок окна
         settings.window.asynchronous = false; //Используем синхронный режим обработки кадров
         settings.useDeveloperTools = true;
         settings.writeLicenseFile = false; //Не создавать файл лицензии
         settings.dataDir = "/home/vit/roengine/data/"; //Здесь лежат файлы с текстурами, моделями и т.д.

         App application(settings);  //Передаем settings в конструктор
         return application.run();   //Запускаем бесконечный цикл
}

Последние две строки можно заменить одной: "return App(settings).run();"

Тут может возникнуть резонный вопрос: для чего создавать App и делать его потомком GApp, почему бы просто не использовать базовый GApp? Ответ станет понятен из небольшого объяснения далее.

GApp не содержит конкретных реализаций методов обработки кадров, рендеринга моделей, теней, света, обработки нажатия клавиш и т.д. Он лишь предоставляет Вам интерфейс (API) для ваших собственных реализаций этих методов. Т.е. если бы это все в нем было бы заранее "прошито", то вы могли бы использовать это только в той форме, в которой оно было скомпилировано в бинарник и никак иначе. Выход был бы только один: написать свой собственный GApp. Вместо этого Морган сделал весьма красивое решение: создал базовый класс GApp, который содержит только логику, но не конкретную реализацию. Вам же лишь остается унаследовать от GApp необходимые методы и с помощью виртуальных функций переопределить их, описав в них уже конкретную реализацию ваших функций. Таким образом, создание объекта класса, наследующего открытые методы GApp, является практически обязательным. Кроме случаев, когда вы пишете полностью свой фреймворк, естественно.

void GApp::onPose(Array< Surface::Ref > &posed3D, Array< Surface2D::Ref > &posed2D)

У каждой модели в G3D есть параметр типа G3D::Surface. Surface это некое абстрактное понятие, которое описывает состояние модели на текущий момент (геометрия, положение, материал и т.д.). Сам Морган называет это snapshot (снимок), что весьма точно отражает смысл. Именно этот самый "снимок" и рендерится в кадре. ArticulatedModel::pose() заставляет объект скинуть свой "снимок" в заданный контейнер, откуда он позже может быть отрендерен в GApp::onGraphics3D() или в своей собственной функции.

Пример:

Code

//Создаем указатель на модель и загружаем ее из файла
ArticulatedModel::Ref model = ArticulatedModel::fromFile("data/3ds/superman.3ds");

void App::onPose(Array<Surface::Ref>& posed3D)
{
//Скидываем "снимок" модели в posed3D
         model->pose(posed3D);
}

void App::onGraphics3D(RenderDevice *rd, Array<Surface::Ref>& posed3D)
{
         ...
//Рендерим posed3D в кадр
         Surface::sortAndRender(rd, defaultCamera, posed3D, lighting,...);
         ...
}

Однако помимо скидывания своего "снимка" в методе pose(), можно еще и скидывать свои координаты в пространстве. Метод ArticulatedModel::pose(Surface::Ref &surface3D) является перегруженной функцией. Помимо указанной есть еще одна его форма: ArticulatedModel::pose(Surface::Ref &surface3D, CoordinateFrame cframe).

CoordinateFrame это ничто иное как матрица размерностью 4x4 (четвертая строка в ней всегда равна [0 0 0 1], поэтому она не хранится). cframe в данной функции хранит положение объекта в пространстве. Таким образом получив это значение в pose() мы можем перемещать объект. Давайте попробуем "посадить" камеру в кабину космического корабля.

Пример:

Code

//Создаем указатель на модель и загружаем ее из файла
ArticulatedModel::Ref model = ArticulatedModel::fromFile("data/3ds/spaceship.3ds");

//Здесь будет сохраняться положение корабля
CoordinateFrame cframe;

void App::onPose(Array<Surface::Ref>& posed3D)
{
//Скидываем "снимок" модели в posed3D, а положение в пространстве в cframe
         model->pose(posed3D, cframe);
}

//Привязываем камеру к cframe
void App::onSimulation(RealTime rdt, SimTime sdt, SimTime idt)
{
         defaultCamera.getCoordinateFrame(cframe);
}

void App::onGraphics3D(RenderDevice *rd, Array<Surface::Ref>& posed3D)
{
         ...
//Рендерим posed3D в кадр
         Surface::sortAndRender(rd, defaultCamera, posed3D, lighting,...);
         ...
}

void GApp::onGraphics(RenderDevice *rd, Array< Surface::Ref > &surface, Array< Surface2D::Ref > &surface2D)

Данный метод реализует покадровый рендеринг изображения. Метод вызывается автоматически. Если вы когда-нибудь работали с "голым" OpenGL и библиотекой glut, то этот метод отдаленно можно сравнить с вызовом glutMainLoop().
класс RenderDevice

Абстрактный интерфейс вывода. Т.е. через методы этого класса осуществляется взаимодействие с функциями OpenGL.

void setColorClearValue (const Color4 &c)

Метод, который устанавливает каким цветом будет отчищаться кадр. Данный метод это обычный вызов в OpenGL glClearColor();

void clear(bool clearColor, bool clearDepth, bool clearStencil);

Метод, который очищает кадр, обрабатываемый рендером. Перегруженный метод, имеет две формы:

Code
void clear();
void clear(bool clearColor, bool clearDepth, bool clearStencil);

Первый это краткая запись второго с установленными в значение истина тремя аргументами. Метод практически всегда является обязательным - без него текущий кадр будет накладываться на предыдущий.

Данный метод это обычный вызов в OpenGL glClear();

swapBuffers()

Принудительно поменять местами задний (где происходит рендеринг) и передний буфер (то, что мы в данный момент видим).

push2D() и pop2D()

Первый метод перевод рендер в систему 2D-координат, второй возвращает в обычное состояние. Обязательно используются в паре. По историческим причинам так сложилось, что двухмерной системе координат точки (0, 0) это верхний левый угол экрана или изображения. Абсцисса (ось X) увеличивается вправо, ордината (ось Y) вниз. Режим 2D-координат это идеальное место чтобы нарисовать прицел, главное меню или любое другое двухмерное изображение.

Попробуем изобразить заставку в момент начальной загрузки игры.

Code
void App::renderSplash() {
      Texture::Ref splash;
      Texture::Settings settings;
      settings.wrapMode = WrapMode::CLAMP;
      splash = Texture::fromFile("data/splash.jpg", ImageFormat::AUTO(), Texture::DIM_2D, settings);

      /*Очищаем экран от предыдущих кадров*/
      renderDevice->clear();

      /*Переводим устройство вывода в режим 2D-координат*/
      renderDevice->push2D();

      renderDevice->setTexture(0, splash);
      renderDevice->setBlendFunc(RenderDevice::BLEND_SRC_ALPHA,
        RenderDevice::BLEND_ONE_MINUS_SRC_ALPHA);
        Draw::rect2D(
          Rect2D::xywh(renderDevice->width()/2 - 400, 0, 800, 1200),      
            renderDevice, Color4(1,1,1,0.7f)
        );

      debugFont->draw2D(renderDevice, "Starting game...", renderDevice->viewport().center(), 24,      
         Color3::white(), Color4::clear(), GFont::XALIGN_CENTER, GFont::YALIGN_BOTTOM);

      /*Возвращаем устройство вывода в стандартный режим*/
      renderDevice->pop2D();

      /*Меняем местами передний и задний буфер*/
      renderDevice->swapBuffers();

      /*Показываем изображение в течении 3 секунд*/
      System::sleep(3);
}

Необходимость принудительно менять местами буферы в предпоследней строке продиктована тем, что функция рисования заставки вызывается вне контекста блоков beginFrame() и endFrame() (о них ниже) и поэтому мы должны самостоятельно озаботиться тем, что бы изображение появилось на экране. Вы же, надеюсь, помните что в заднем буфере происходит рендеринг, а в переднем выводится изображение.

beginOpenGL() и endOpenGL()

Методы вызываются без аргументов и используются обязательно в паре. Первый метод переводит рендер в режим "голого" OpenGL, при котором становится возможно оперировать функциями и типами данных OpenGL напрямую (устанавливает значение переменной RenderDevice::m_inRawOpenGL в истину). Второй метод возвращает рендер в стандартный режим (переводит RenderDevice::m_inRawOpenGL в ложь).

Давайте попробуем построить куб с помощью стандартых функций OpenGL, используя RenderDevice.

Code
rd->beginOpenGL();
      glBegin ( GL_QUADS );
       glVertex3f ( 1.0f, 1.0f, 2.0f );
       glVertex3f ( 2.0f, 1.0f, 2.0f );
       glVertex3f ( 2.0f, 2.0f, 2.0f );
       glVertex3f ( 1.0f, 2.0f, 2.0f );

       glVertex3f ( 2.0f, 1.0f, 1.0f );
       glVertex3f ( 1.0f, 1.0f, 1.0f );
       glVertex3f ( 1.0f, 2.0f, 1.0f );
       glVertex3f ( 2.0f, 2.0f, 1.0f );

       glVertex3f ( 1.0f, 1.0f, 1.0f );
       glVertex3f ( 1.0f, 1.0f, 2.0f );
       glVertex3f ( 1.0f, 2.0f, 2.0f );
       glVertex3f ( 1.0f, 2.0f, 1.0f );

       glVertex3f ( 2.0f, 1.0f, 2.0f );
       glVertex3f ( 2.0f, 1.0f, 1.0f );
       glVertex3f ( 2.0f, 2.0f, 1.0f );
       glVertex3f ( 2.0f, 2.0f, 2.0f );

       glVertex3f ( 1.0f, 2.0f, 2.0f );
       glVertex3f ( 2.0f, 2.0f, 2.0f );
       glVertex3f ( 2.0f, 2.0f, 1.0f );
       glVertex3f ( 1.0f, 2.0f, 1.0f );

       glVertex3f ( 2.0f, 1.0f, 2.0f );
       glVertex3f ( 1.0f, 1.0f, 2.0f );
       glVertex3f ( 1.0f, 1.0f, 1.0f );
       glVertex3f ( 2.0f, 1.0f, 1.0f );
      glEnd ();
rd->endOpenGL();
класс Film      
класс Material      
класс ArticulatedModel      
класс ArticulatedModel::Preproccess      

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

Пример, показывающий как загрузив обычный шар, превратить его в стекляный шар:
//путь к модели сферы

Code

std::string filename = System::findDataFile("sphere.ifs");

//Создаем материал "стекло"
Material::Specification glass;

//Описываем материал "стекло"
glass.setLambertian(Color3::zero());
glass.setTransmissive(Color3::white() * 0.9f); //стекло будет безцветное
glass.setSpecular(Color3::white() * 0.05f);
glass.setGlossyExponentShininess(200);
glass.setEta(1.5f, 1.0f);
glass.setRefractionHint(RefractionQuality::DYNAMIC_FLAT);

//Создаем объект, содержащий описание материала для модели
ArticulatedModel::Preprocess p;

//Теперь объект "p" содержит описание матариала. Т.е. любая модель, использующая "p", станет стекляной
p.materialOverride = Material::create(glass);

//делаем модель стекляной (второй аргумент в функции "fromFile()")
ArticulatedModel::Ref model = ArticulatedModel::fromFile(filename, p);
класс BumpMap
класс SuperShader
класс _BSPMap::Map


Купил торку и не парюсь.
Ключ Windows 10 Pro от 499р


Сообщение отредактировал pekar - Пятница, 09 Июля 2010, 18:57
  • Страница 1 из 1
  • 1
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг