[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Форум » Игровые движки » IrrLicht Engine » Туториал №8: Спецэффекты
Туториал №8: Спецэффекты
MerGC_TeamДата: Четверг, 03.04.2014, 16:35 | Сообщение # 1
Веселый админ
Группа: Администраторы
Сообщений: 32
Статус: Оффлайн
Этот урок посвящен спецэффектам. В нем вы узнаете достаточно много полезных вещей: как реализовывать тени, работать с системой частиц, выводить билборды, помещать на сцену динамические источники света и имитировать водные поверхности.

Начнем как и обычно... Подключим заголовочный файл IrrLicht, объявим пространстов имен 'irr' включенным. Но мы хотим использовать в уроке тени, поэтому при вызове createDevice() параметр устанавливающий использования трафаретного буфера установим в true. Если ваша видеокарта не поддерживает трафаретный буфер, то Irrlicht сам отключит его использование, но в некоторых случаях пример выполняется медленно, поэтому если теней вы не увидели, а пример выполняется медленно, то при запуске примера лучше отказаться от них и тогда все будет нормально.

Код
#include < irrlicht.h >
#include < iostream >
#include "driverChoice.h"

using namespace irr;

int main()
{
         // спрашиваем пользователя хочет ли он использовать тени

         char i;
         printf("Please press 'y' if you want to use realtime shadows.n");

         std::cin >> i;

         const bool shadows = (i == 'y');

         // предлагаем пользователю выбрать драйвер (DirectX, OpenGL и т.д.)
         video::E_DRIVER_TYPE driverType=driverChoiceConsole();
         if (driverType==video::EDT_COUNT)  return 1;


Создаем корневой объект(движок) IrrLicht, последний параметр отвечает за тени, его значение мы запростили чуть выше

Код
IrrlichtDevice *device =  createDevice(driverType, core::dimension2d< u32 >(640, 480), 16, false, shadows);

         if (device == 0)  return 1; // произошла ошибка, движок не создан - выходим.

         video::IVideoDriver* driver = device->getVideoDriver();
         scene::ISceneManager* smgr = device->getSceneManager();


Для создания обстановки загрузим .3ds файл с маленькой комнаткой, которая смоделирована в Anim8or и экспортирована в 3ds формат, потому что Irrlicht не поддерживает его родной .an8 формат. Я не крут ни разу в 3d моделировании, поэтому текстуры там натянуты на троечку. К счастью я хороший программист и в движке есть возможность маппить текстуры: и я замапил текстуры с помощью метода planar texture mapping "натравив" на модель метод манипулятора makePlanarTextureMapping. Если вам интересно оценить мой скил(навык) 3d моделирования, то закоментируйте ту строку и увидите после запуска что я намапил в редакторе.

Код
scene::IAnimatedMesh* mesh = smgr->getMesh("../../media/room.3ds");

         smgr->getMeshManipulator()->makePlanarTextureMapping(mesh->getMesh(0), 0.004f);

         scene::ISceneNode* node = 0;

         node = smgr->addAnimatedMeshSceneNode(mesh);
         node->setMaterialTexture(0, driver->getTexture("../../media/wall.jpg"));
         node->getMaterial(0).SpecularColor.set(0,0,0,0);


Добавляем на сцену анимированную воду. В движке реализован класс, который загружает указанный ему набор вершин(модель) и соответственно заданным параметрам колеблет образованную им поверхность. А если мы еще создадим для воды материал типа EMT_REFLECTION_2_LAYER то это вообще будет выглядеть круто. И так в качестве модели мы сгенерируем холмы без холмов, т.е. вызовем генератор холмистых поверхностей с нулевым разбросом высот, на основе полученного меша(набора вершин) создадим на сцене узел(ноду) имитирующую воду addWaterSurfaceSceneNode, спозиционируем ее и привяжем материал с двумя текструрами и отражающим слоем.

Код
mesh = smgr->addHillPlaneMesh( "myHill",
                 core::dimension2d< f32 >(20,20),
                 core::dimension2d< u32 >(40,40), 0, 0,
                 core::dimension2d< f32 >(0,0),
                 core::dimension2d< f32>(10,10));

         node = smgr->addWaterSurfaceSceneNode(mesh->getMesh(0), 3.0f, 300.0f, 30.0f);
         node->setPosition(core::vector3df(0,7,0));

         node->setMaterialTexture(0, driver->getTexture("../../media/stones.jpg"));
         node->setMaterialTexture(1, driver->getTexture("../../media/water.jpg"));

         node->setMaterialType(video::EMT_REFLECTION_2_LAYER);


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

Код
// создаем источник света

         node = smgr->addLightSceneNode(0, core::vector3df(0,0,0), video::SColorf(1.0f, 0.6f, 0.7f, 1.0f), 800.0f);
         scene::ISceneNodeAnimator* anim = 0;
         anim = smgr->createFlyCircleAnimator (core::vector3df(0,150,0),250.0f);
         node->addAnimator(anim);
         anim->drop();

         // цепляем билборд к источнику света

         node = smgr->addBillboardSceneNode(node, core::dimension2d(50, 50));
         node->setMaterialFlag(video::EMF_LIGHTING, false);
         node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
         node->setMaterialTexture(0, driver->getTexture("../../media/particlewhite.bmp"));


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

Существует несколько эмиттеров, для примера точечный эмиттер, который извергает частицы из одной определенной точки. Если нужного вам эмиттера нет в движке, вы без особого труда добавите необходимый, надо создать класс унаследованный от IParticleEmitter и присоединить его к системе частиц методом setEmitter(). В этом примере мы создадим кубический эмиттер, который создает частицы случайным образом в пределах описанного нами кубического объема. Параметры нашего эмиттера: направление частиц, минимальное и максимальное число частиц в секунду, цвет и минимальное и максимальное время жизни частиц.

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

После настройки эмиттеров/аффекторов, мы добавим матерал для симулирования костра. Комбинируюя материалы, текстуры, эмиттеры и аффекторы можно симулировать дым, дождь, снег, взрывы и т.п.

Код
// добавляем систему частиц

         scene::IParticleSystemSceneNode* ps = smgr->addParticleSystemSceneNode(false);

         scene::IParticleEmitter* em = ps->createBoxEmitter(
                 core::aabbox3d< f32 >(-7,0,-7,7,1,7), // размер эмиттера(куба)
                 core::vector3df(0.0f,0.06f,0.0f),   // начальное направление
                 80,100,                             // частота испускания (мин,макс)
                 video::SColor(0,255,255,255),       // самый темный цвет
                 video::SColor(0,255,255,255),       // самый яркий цвет
                 800,2000,0,                         // време жизни (мин,макс), угол
                 core::dimension2df(10.f,10.f),         // минимальный размер частиц
                 core::dimension2df(20.f,20.f));        // максимальный размер частиц

         ps->setEmitter(em); // отдаем эмиттер системе
         em->drop(); // а лично нам он не нужен

         scene::IParticleAffector* paf = ps->createFadeOutParticleAffector();

         ps->addAffector(paf); // отдаем аффектор системе и дропаем, т.к. нам он не нужен
         paf->drop();

         ps->setPosition(core::vector3df(-70,60,40));
         ps->setScale(core::vector3df(2,2,2));
         ps->setMaterialFlag(video::EMF_LIGHTING, false);
         ps->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false);
         ps->setMaterialTexture(0, driver->getTexture("../../media/fire.bmp"));
         ps->setMaterialType(video::EMT_TRANSPARENT_VERTEX_ALPHA);


Добавляем на сцену узел(ноду) объемного источника света, который будет освещать сцену мерцающим светом. Чтобы свет мерцал мы привяжем к источнику текстурку и аниматор, который ее анимирует.

Код
scene::IVolumeLightSceneNode * n = smgr->addVolumeLightSceneNode(0, -1,
                    32,                    // Subdivisions on U axis
                    32,                    // Subdivisions on V axis
                    video::SColor(0, 255, 255, 255), // foot color
                    video::SColor(0, 0, 0, 0));      // tail color

         if (n)
         {
                 n->setScale(core::vector3df(56.0f, 56.0f, 56.0f));
                 n->setPosition(core::vector3df(-120,50,40));

                 // грузим текстуру для анимации
                 core::array< video::ITexture* > textures;
                 for (s32 g=7; g > 0; --g)
                 {
                         core::stringc tmp;
                         tmp = "../../media/portal";
                         tmp += g;
                         tmp += ".bmp";
                         video::ITexture* t = driver->getTexture( tmp.c_str() );
                         textures.push_back(t);
                 }

                 // создаем аниматор для текстуры
                 scene::ISceneNodeAnimator* glow = smgr->createTextureAnimator(textures, 150);

                 // добавляем аниматор и источнику света
                 n->addAnimator(glow);

                 // дробаем аниматор за ненадобностью нам, а у системы он уже есть - отдали строчкой выше.
                 glow->drop();
         }


Ну и последним эффектом будет тень отбрасываемая персонажем. Для этого загрузим .x и поставим в центр комнаты. Для создания тени надо всего лишь добавить узел(ноду) методом addShadowVolumeSceneNode(). Цвет теней устанавливается только глобально вызовом ISceneManager::setShadowColor(). Вуаля, персонаж отбрасывает тень.

Т.к. изначально персонаж великоват для комнаты, мы его отмаштабируем методом setScale(). А т.к. персонаж освещается динамически, мы должны нормализовать все его нормали, чтобы реакция на свет была корректной. Но это только если модель масштабируется на сцене, иначе в этом нет необходимости.

Код
// добавляем анимированный персонаж

         mesh = smgr->getMesh("../../media/dwarf.x");
         scene::IAnimatedMeshSceneNode* anode = 0;

         anode = smgr->addAnimatedMeshSceneNode(mesh);
         anode->setPosition(core::vector3df(-50,20,-60));
         anode->setAnimationSpeed(15);

         // добавляем тени
         anode->addShadowVolumeSceneNode();
         smgr->setShadowColor(video::SColor(150,0,0,0));

         // маштабируем модель
         // нормализуем нормали
         anode->setScale(core::vector3df(2,2,2));
         anode->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);


Добавляем на сцену камеру и начинаем в цикле рисовать сцену

Код
scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS();
         camera->setPosition(core::vector3df(-50,50,-150));

         // прячем указатель мыши
         device->getCursorControl()->setVisible(false);

         s32 lastFPS = -1;

         while(device->run())
         if (device->isWindowActive())
         {
                 driver->beginScene(true, true, 0);

                 smgr->drawAll();

                 driver->endScene();

                 const s32 fps = driver->getFPS();

                 if (lastFPS != fps)
                 {
                         core::stringw str = L"Irrlicht Engine - SpecialFX example [";
                         str += driver->getName();
                         str += "] FPS:";
                         str += fps;

                         device->setWindowCaption(str.c_str());
                         lastFPS = fps;
                 }
         }

         device->drop();

         return 0;
}


Вот и все, компилируем, запускаем, наслаждаемся.
 
Форум » Игровые движки » IrrLicht Engine » Туториал №8: Спецэффекты
  • Страница 1 из 1
  • 1
Поиск: