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 для вас не секрет.
|
|
| |