[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Форум » Игровые движки » IrrLicht Engine » Туториал №3: Собственный тип ноды (сложность: высокая)
Туториал №3: Собственный тип ноды (сложность: высокая)
MerGC_TeamДата: Пятница, 28.02.2014, 22:26 | Сообщение # 1
Веселый админ
Группа: Администраторы
Сообщений: 32
Статус: Оффлайн
Этот туториал описывает как создать свою собственную ноду и разместить ее на сцене. Это может понадобится, если
те возможности движка, которые вам нужны, еще не реализованы. Для
примера, если вы хотите написать какой-нибудь особенный портальный
рендерер или ноду реализующую генерацию ландшафта по каким-то вашим
собственным законам. Внедрить ваши желания в движок IrrLicht очень легко
посредством создания своих типов узлов(нод) для сцены.
Я постараюсь сделать туториал доступным: очень коротким, умещенным в один .cpp файл, с сохранением стиля предыдущих туториалов.
В начале включаем в проект заголовочные файлы, указываем, что используем пространство имен ‘irr’.

Код
#include <irrlicht.h>
#include "driverChoice.h"
   
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#endif
   
using namespace irr;
using namespace video;


Здесь начинается самая главная часть туториала: мы создаем класс своей собственной ноды. Для простоты, это не будет рендерер с какой-либо хитрой техникой, а функционал рисующий тетраэдр – 3d объект включающий 4 вершины и не более. Замечу что для этого случая нет необходимости создавать свои собственные реализации для нод, достаточно создать модель в 3d редакторе и загрузить ее геометрию в irr::scene::IMeshSceneNode. Задача этого примера на “пальцах” проиллюстрировать создание своих собственных нод для сцены.

Для того чтобы мы могли нашу ноду добавить на сцену, она должна быть унаследована от интерфейсного класса irr::scene::ISceneNode и переопределить некоторые его методы.

Код
class CSampleSceneNode : public scene::ISceneNode
{


Для начала, объявим несколько переменных: границы объема(bounding box), 4 вершины и материал тетраэдера.

Код
core::aabbox3d Box;
video::S3DVertex Vertices[4];
video::SMaterial Material;


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

Код
public:
CSampleSceneNode(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id):
scene::ISceneNode(parent, mgr, id)
{
Material.Wireframe = false;
Material.Lighting = false;
Vertices[0] = S3DVertex(0,0,10, 1,1,0, SColor(255,0,255,255), 0, 1);
Vertices[1] = S3DVertex(10,0,-10, 1,0,0, SColor(255,255,0,255), 1, 1);
Vertices[2] = S3DVertex(0,20,0, 0,1,1, SColor(255,255,255,0), 1, 0);
Vertices[3] = S3DVertex(-10,0,-10, 0,0,1, SColor(255,0,255,0), 0, 0);


Движку Irrlicht необходимо знать bounding box ноды. Эта информация используется для автоматического отсечения невидимых поверхностей и др. Отсюда, нам необходимо определить bounding box для наших 4х вершин. Если у вас нет необходимости в использовании bounding box для автоматического отсечения и/или не хотите его использовать эту функцию вообще, вы можете вызвать irr::scene::ISceneNode::setAutomaticCulling() со значением irr::scene::EAC_OFF.

Код
Box.reset(Vertices[0].Pos);
for (s32 i=1; i<4; ++i)
Box.addInternalPoint(Vertices[i].Pos);
}


В движке прежде чем любая нода нарисуется, менеджером сцены будет вызван ее обработчик irr::scene::ISceneNode::OnRegisterSceneNode() . В этом обработчике нода определяет когда она хочет отобразится и хочет ли отобразиться вообще. Это необходимо, когда нужно изменить порядок рендеринга ноды, т.е. когда менеждер сцены вызовет ее метод irr::scene::ISceneNode::render(). Для примера, ноды отрисовываются последовательно одна за другой отсортированные по типам. Сначала рендерятся ноды камер, потом источников света и т.д. Сейчас мы не будем указывать движку когда рендерить нашу ноду, но если вам захочеться вокнуть отрисовку вашей ноды на этап отрисовки камеры вы можете вызвать SceneManager->registerNodeForRendering(this, SNRT_LIGHT_AND_CAMERA); А уже после метод irr::scene::ISceneNode::OnRegisterSceneNode() родительского класса.

Код
virtual void OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}


В методе render() происходит следующее – нода рисует сама себя, мы переопределим этот метод своим кодом рисования тетраэдера.

Код
virtual void render()
{
u16 indices[] = { 0,2,3, 2,1,3, 1,0,3, 2,0,1 };
video::IVideoDriver* driver = SceneManager->getVideoDriver();
driver->setMaterial(Material);
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
driver->drawVertexPrimitiveList(&Vertices[0], 4, &indices[0], 4, video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);
}


По завершению добавим еще тройку нужных методов. irr::scene::ISceneNode::getBoundingBox() возвращает bounding box ноды, irr::scene::ISceneNode::getMaterialCount() возвращает количество материалов использованных в ноде (в нашем случае вернет 1) и irr::scene::ISceneNode::getMaterial() возвращающий материал относительно запрошенного индекса, а так как материал у нас один, то независимо от индекса мы будет возвращать значение переменной Material.

Код
virtual const core::aabbox3d& getBoundingBox() const
{
return Box;
}
virtual u32 getMaterialCount() const
{
return 1;
}
   
virtual video::SMaterial& getMaterial(u32 i)
{
return Material;
}
};


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

Код
int main()
{
// запрашиваем драйвер, типа directx, opengl и т.д.
video::E_DRIVER_TYPE driverType=driverChoiceConsole();
if (driverType==video::EDT_COUNT)
return 1; // ничего не выбрано - выходим из программы.
// создаем корневой объект
IrrlichtDevice *device = createDevice(driverType,
core::dimension2du(640, 480), 16, false);
// ошибка создания движка для выбранного драйвера, выходим из программы.
if (device == 0) return 1;
   
// определяем заголовок окна, пару вспомогательных указателей, добавляем камеру
device->setWindowCaption(L"Custom Scene Node - Irrlicht Engine Demo");
   
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
smgr->addCameraSceneNode(0, core::vector3df(0,-40,0), core::vector3df(0,0,0));


Создаем ноду на основе нашего собственного класса. Я не проверяю результат работы new, т.к. он сгенерит исключительную ситуацию раньше чем вернет 0 при сбое. При нормальном ходе конструктор ноды создав ноду установить счетчик ссылок в 1 и далее родительский конструкто увеличит его еще на 1 прицепив к сцене, поэтому необходимо вызвать drop. Вообще, хорошая практика вызывать drop после того как вы закончили работать с объектом и отдали его на попечение движка.

Код
CSampleSceneNode *myNode =
new CSampleSceneNode(smgr->getRootSceneNode(), smgr, 666);


Чтобы было чем полюбоваться кроме утомительного наблюдения за “мертвым” тетраэдером, оживим его добавив аниматор, который будет вращать нашу ноду irr::scene::ISceneManager::createRotationAnimator() .

Код
scene::ISceneNodeAnimator* anim = smgr->createRotationAnimator(
core::vector3df(0.8f, 0, 0.8f));
if(anim)
{
myNode->addAnimator(anim); // присоединяем аниматор к ноде


После присоединения надо вызвать irr::IReferenceCounted::drop() для аниматора, т.к. аниматор создан одной из функций типа createFoo() ну и не плохо было бы почитать эту статью в ней подробно описано что и для чего метод drop().

Код
anim->drop();
anim = 0; // обнуляем указатель на всякий пожарный
}


Теперь мы закончили с созданием CSampleSceneNode и должны сбросить счетчик. Это не удалит объект, т.к. он присоединен к сцене, пока вы сами не удалите сцену целиком или именно эту ноду вызвав для нее метод remove().

Код
myNode->drop();
myNode = 0; // обнуляем указатель на всякий пожарный


Теперь запускаем главный цикл.

Код
u32 frames=0;
while(device->run())
{
driver->beginScene(true, true, video::SColor(0,100,100,100));
smgr->drawAll();
driver->endScene();
   
if (++frames==100)
{
core::stringw str = L"Irrlicht Engine [";
str += driver->getName();
str += L"] FPS: ";
str += (s32)driver->getFPS();
device->setWindowCaption(str.c_str());
frames=0;
}
}
device->drop();
return 0;
}


Все. Компилируем и запускаем.
 
Форум » Игровые движки » IrrLicht Engine » Туториал №3: Собственный тип ноды (сложность: высокая)
  • Страница 1 из 1
  • 1
Поиск: