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

Рендеринг ландшафта в IrrLicht базируется на Sprintz' GeoMipMapSceneNode, выражаю его разработчикам великую благодарность. DeusXL разработал простой и элегантный способ сторить большие области с помощью маленьких карт вершин (heightmaps).

Начнем традиционно, подключим заголовочный файл, объявим пространство имен irr, далее создадим обработчик событий: клавиша 'W' будет переключать wireframe режим (рисование только каркаса полигонов), клавиша 'P' режим pointcloud (рисование только вершин полигонов) и клавиша 'D' будет переключать текстуры - слошную и детальную.
Код
#include < irrlicht.h >
#include "driverChoice.h"

using namespace irr;  

class MyEventReceiver : public IEventReceiver
{
public:

         MyEventReceiver(scene::ISceneNode* terrain, scene::ISceneNode* skybox, scene::ISceneNode* skydome) :
                 Terrain(terrain), Skybox(skybox), Skydome(skydome), showBox(true)
         {
                 Skybox->setVisible(true);
                 Skydome->setVisible(false);
         }

         bool OnEvent(const SEvent& event)
         {
                 // проверка нажатия 'W' или 'D'
                 if (event.EventType == irr::EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown)
                 {
                         switch (event.KeyInput.Key)
                         {
                         case irr::KEY_KEY_W: // переключаемся в режим wireframe
                    Terrain->setMaterialFlag(video::EMF_WIREFRAME,
                    !Terrain->getMaterial(0).Wireframe);
                    Terrain->setMaterialFlag(video::EMF_POINTCLOUD, false);
                    return true;
                         case irr::KEY_KEY_P: // переключаемся в режим pointcloud
                    Terrain->setMaterialFlag(video::EMF_POINTCLOUD,
                    !Terrain->getMaterial(0).PointCloud);
                    Terrain->setMaterialFlag(video::EMF_WIREFRAME, false);
                    return true;
                         case irr::KEY_KEY_D: // переключаем детализацию
                    Terrain->setMaterialType(
                    Terrain->getMaterial(0).MaterialType == video::EMT_SOLID ?
                    video::EMT_DETAIL_MAP : video::EMT_SOLID);
                    return true;
                         case irr::KEY_KEY_S: // переключаем скайдом и скайбокс
                    showBox=!showBox;
                    Skybox->setVisible(showBox);
                    Skydome->setVisible(!showBox);
                    return true;
                         default:
                    break;
                         }
                 }

                 return false;
         }

private:
         scene::ISceneNode* Terrain;
         scene::ISceneNode* Skybox;
         scene::ISceneNode* Skydome;
         bool showBox;
};


Начнем писать главную функцию как обычно, но движок создадим с расширенным набором параметров.
Код
int main()
{
         // запрашиваем видеодрайвер (DirectX, OpenGL и т.п.)
         video::E_DRIVER_TYPE driverType=driverChoiceConsole();
         if (driverType==video::EDT_COUNT) return 1;

         // создадим корневой объект(движок) с набором расширенных параметров
         // это, если необходимо, делается с помощью структуры irr::SIrrlichtCreationParameters
         irr::SIrrlichtCreationParameters params;
         params.DriverType=driverType;
         params.WindowSize=core::dimension2d< u32 >(640, 480);
         IrrlichtDevice* device = createDeviceEx(params);

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


Добавим на сцену несколько стандартных вещей: логотип irrlicht, небольшую аннотацию, FPS камеру и спрячем указатель мыши
Код
video::IVideoDriver* driver = device->getVideoDriver();
         scene::ISceneManager* smgr = device->getSceneManager();
         gui::IGUIEnvironment* env = device->getGUIEnvironment();

         driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);

         // добавим логотип irrlicht
         env->addImage(driver->getTexture("media/irrlichtlogo2.png"),
                 core::position2d< s32 >(10,10));

         // установим шрифт по крупнее нежели стандартный
         env->getSkin()->setFont(env->getFont("media/fontlucida.png"));

         // добавим текст помощи
         env->addStaticText(
                 L"Press 'W' to change wireframe modenPress 'D' to toggle detail mapnPress 'S' to toggle skybox/skydome",
                 core::< s32 >rect(10,421,250,475), true, true, 0, -1, true);

         // добавим камеру
         scene::ICameraSceneNode* camera =
                 smgr->addCameraSceneNodeFPS(0,100.0f,1.2f);

         camera->setPosition(core::vector3df(2700*2,255*2,2600*2));
         camera->setTarget(core::vector3df(2397*2,343*2,2700*2));
         camera->setFarValue(42000.0f);

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


Приступим к помещению на сцену ландшафта: добавим узел(ноду) реализующий ландшаф, это делается методом ISceneManager::addTerrainSceneNode(), который мы вызовем с единственным параметром - именем файла текстры реализующей карту высот(heightmap). Карта высот - это текстура в градациях серого, где яркость пикселя определяет высоту вершины в 3д пространстве.

Чтобы наша "земля" была большой, мы ее отмаштабируем с коэффициентами (40, 4.4, 40). Мы не будем помещать на сцену источников света, поэтому отключим его использование для материала нашей "земли". Текстуру terrain-texture.jpg мы будем использовать как основную, а сверху на нее наложим текстуру detailmap3.jpg которая будет детализировать первую. Ну и последний момент, мы зададим масштаб для текстур, т.е. основная у нас ляжет на модель ландшафта целиком, а детальную уменьшим так чтобы на ландшафт ее уместилось 20х20 квадратов.
Код
// добавляем узел(ноду) ландшафта
         scene::ITerrainSceneNode* terrain = smgr->addTerrainSceneNode(
                 "media/terrain-heightmap.bmp",
                 0,                    // родительский узел
                 -1,                    // id узла
                 core::vector3df(0.f, 0.f, 0.f),         // позиция
                 core::vector3df(0.f, 0.f, 0.f),         // поворот
                 core::vector3df(40.f, 4.4f, 40.f),      // маштаб
                 video::SColor ( 255, 255, 255, 255 ),   // цвет вершин
                 5,                    // максимум LOD
                 scene::ETPS_17,                         // размер патча
                 4                    // коэф-т размытия
                 );

         terrain->setMaterialFlag(video::EMF_LIGHTING, false);

         terrain->setMaterialTexture(0,
                         driver->getTexture("media/terrain-texture.jpg"));
         terrain->setMaterialTexture(1,
                         driver->getTexture("media/detailmap3.jpg"));
          
         terrain->setMaterialType(video::EMT_DETAIL_MAP);

         terrain->scaleTexture(1.0f, 20.0f);
         //terrain->setDebugDataVisible ( true );


Для обработки столкновений с ланшафтом надо создать селектор(triangle selector), подробнее о нем можно узнать из туториала №7. Он нам понадобится, чтобы наша камера не могла летать сквозь наш ландшафт, типа мы его сделаем физически твердым.
Код
// создаем селектор для ландшафта
         scene::ITriangleSelector* selector
                 = smgr->createTerrainTriangleSelector(terrain, 0);
         terrain->setTriangleSelector(selector);

         // создаем аниматор определяющий столкновения и цепляем его к камере
         scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator(
                 selector, camera, core::vector3df(60,100,60),
                 core::vector3df(0,0,0),
                 core::vector3df(0,50,0));
         selector->drop();
         camera->addAnimator(anim);
         anim->drop();


Если вам понадобится низкоуровневый доступ к данным ландшафта, то это показывается в следующем фрагменте кода.
Код
scene::CDynamicMeshBuffer* buffer = new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT);
         terrain->getMeshBufferForLOD(*buffer, 0);
         video::S3DVertex2TCoords* data = (video::S3DVertex2TCoords*)buffer->getVertexBuffer().getData();
         // получаем массив со списком вершин.
         // --- в этом месте творим с вершинами че хотим ---.
         buffer->drop(); // дропаем массив, если уже натворились.


Создаем скайбокс (куб "застеленный" изнутри шестью текструрами) и скайдом (текстура неба свернутая в шар, горизонтальное сечение которого, пердположительно будет выполнять функцию горизонта). Внутри этих куба и шара будет располагаться наш ландшафт, а переключатся они будут клавишей 'S'.
Код
// создаем скайбокс и скайдом
         driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);

         scene::ISceneNode* skybox=smgr->addSkyBoxSceneNode(
                 driver->getTexture("media/irrlicht2_up.jpg"),
                 driver->getTexture("media/irrlicht2_dn.jpg"),
                 driver->getTexture("media/irrlicht2_lf.jpg"),
                 driver->getTexture("media/irrlicht2_rt.jpg"),
                 driver->getTexture("media/irrlicht2_ft.jpg"),
                 driver->getTexture("media/irrlicht2_bk.jpg"));
         scene::ISceneNode* skydome=smgr->addSkyDomeSceneNode(driver->getTexture("media/skydome.jpg"),16,8,0.95f,2.0f);

         driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);

         // создаем обработчик событий
         MyEventReceiver receiver(terrain, skybox, skydome);
         device->setEventReceiver(&receiver);


Начинаем рисовать.
Код
int lastFPS = -1;

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

                 smgr->drawAll();
                 env->drawAll();

                 driver->endScene();

                 // пишем в заголовок окна число кадров в секунду
                 int fps = driver->getFPS();
                 if (lastFPS != fps)
                 {
                         core::stringw str = L"Terrain Renderer - Irrlicht Engine [";
                         str += driver->getName();
                         str += "] FPS:";
                         str += fps;
                         // пишем высоту ландшафта и позицию камеры
                         str += " Height: ";
                         str += terrain->getHeight(camera->getAbsolutePosition().X,
                    camera->getAbsolutePosition().Z);

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

         device->drop();
          
         return 0;
}


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