Öncelikle başlangıç olarak 2. örnekteki quake3 haritasını yüklüyoruz.
Bu haritanın içinde yürüyecek ve üçgenlerini seçeceğiz.Ayrıca SceneNode seçimi için
3 tane animasyonlu modelde ekliyoruz.Aşağıdaki kod motoru hazırlar ve bir q3 haritası yükler.
Bu kısmın detayları örnek 2 ile aynıdır.
#include <irrlicht.h>
#include <iostream>
using namespace irr;
#pragma comment(lib, "Irrlicht.lib")
int main()
{
// let user select driver type
video::E_DRIVER_TYPE driverType;
printf("Please select the driver you want for this example:\n"\ " (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\ " (d) Software Renderer\n (e) Apfelbaum Software Renderer\n"\ " (f) NullDevice\n (otherKey) exit\n\n");
char i; std::cin >> i;
switch(i) { case 'a': driverType = video::EDT_DIRECT3D9;break; case 'b': driverType = video::EDT_DIRECT3D8;break; case 'c': driverType = video::EDT_OPENGL; break; case 'd': driverType = video::EDT_SOFTWARE; break; case 'e': driverType = video::EDT_SOFTWARE2;break; case 'f': driverType = video::EDT_NULL; break; default: return 0; }
// create device
IrrlichtDevice *device = createDevice(driverType,
core::dimension2d<s32>(640, 480), 16, false);
if (device == 0) return 1; // could not create selected driver.
video::IVideoDriver* driver = device->getVideoDriver(); scene::ISceneManager* smgr = device->getSceneManager();
device->getFileSystem()->addZipFileArchive ("../../media/map-20kdm2.pk3");
scene::IAnimatedMesh* q3levelmesh = smgr->getMesh("20kdm2.bsp");
scene::ISceneNode* q3node = 0;
if (q3levelmesh)
q3node = smgr->addOctTreeSceneNode(q3levelmesh->getMesh(0));
|
Örnek 2 deki gibi haritamızı yükledik. Şimdi farklı birşey yapıyoruz ve bir üçgen seçici(triangle selector)
nesnesi yaratıyoruz.Üçgen seçici nesnesi SceneNode'lardan üçgenleri çekip kullanabilmemizi(mesela çarpışma testi için) sağlayan bir
sınıftır.Farklı üçgen seçici tipleri vardır ve hepsi ISceneManager ile yaratılabilinir. Bu örnekte bir
OctTreeTriangleSelector nesnesi oluşturuyoruz.OctTreeTriangleSelector üçgen çıktısını bir derece optimize edecektir ki bu
q3 haritaları gibi büyük mesh'lerde çok faydalıdır.
Üçgen seçiciyi yarattıktan sonra q3node'a bağlıyoruz.Bu önemli bir adım değil fakat
artık üçgen seçiciyle ilgilenmemize gerek yok(mesela kullanımı bitince silmemize gerek yok).
scene::ITriangleSelector* selector = 0;
if (q3node)
{
q3node->setPosition(core::vector3df(-1370,-130,-1400));
selector = smgr->createOctTreeTriangleSelector(
q3levelmesh->getMesh(0), q3node, 128);
q3node->setTriangleSelector(selector);
selector->drop();
} |
Örnek 2 deki gibi haritada rahatça dolaşabilmek için bir FPS kamerası ekliyoruz.
2. örnekten farklı olarak kameraya bir çarpışma tepkisi animatörü(Collision Response Animator) ekliyoruz.
Bu animatör bağlandığı node'un duvarlardan geçmesini önler ve yerçekiminden etkilenmesini sağlar.
Burada tek yapmamız gereken şey animatöre mekanın nasıl olduğunu ve yerçekimi miktarını bildirmek.
Bu animatörü kameraya bağladıktan sonra çarpışma testi için başka birşey yapmamıza gerek kalmıyor ve herşey otomatik
olarak gerçekleşiyor.Aşağıdaki diğer çarpışma testi kodları diğer 2 tip çarpışma testi çeşidi içindir.
Burada fazladan ekleyebileceğimiz birşey de şu ki bu animatörü bir kameraya bağlayabildiğimiz gibi
diğer tüm SceneNode'lara bağlayabiliriz.Hatta diğer animatörlerle beraberde çalışabilirler.
Gördüğünüz gibi Irrlicht motorunda çarpışma kontrolü gayet kolay.
Şimdi "createCollisionResponseAnimator()" metodunun parametrelerine yakından bakacağız.
İlk parametre üçgen seçici.Üçgen seçici mekanı temsil ediyor.Q3 haritasını oluştururken seçiciyide oluşturuyoruz.
2. parametre çarpışmadan etkilenecek SceneNode.Bu örnekte çarpışmadan etkilenen öğe kamera.
3. parametre 2. parametredeki nesnenin büyüklüğü.Burada bir ellipsoid'in çapı olarak veriliyor.Sonraki parametre yerçekiminin yönü ve büyüklüğünü belirtiyor.Bu değeri (0,0,0) olarak ayarlayarak
yerçekimini iptal edebilirsiniz.Son parametre bir öteleme vektörü.Bu kameramız ile elipsoid arasındaki öteleme
miktarını belirtmekte.Bunu (0,0,0) olarak ayarlarsak aynı yerde olacaklardır fakat insanın gözünün vücudunun
üst kısmında olduğunu varsayarsak nesnemizi buradaki gibi 50 birim yukarı koymamız mantıklı olacaktır.
Evet artık çarpışma testimiz çalışır halde.
scene::ICameraSceneNode* camera = camera = smgr->addCameraSceneNodeFPS(0,100.0f,300.0f);
camera->setPosition(core::vector3df(-100,50,-150));
scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator(
selector, camera, core::vector3df(30,50,30),
core::vector3df(0,-3,0),
core::vector3df(0,50,0));
camera->addAnimator(anim);
anim->drop(); |
Çarpışma testi irrlicht motorunda kolay olduğu için diğer 2 yöntemide anlatacağız.
Ama bundan önce bir ön hazırlık olarak sahneye 3 tane animasyonlu model ekliyoruz.
Seçili modeli belirtmek için bir ışık ve çarpışma noktasını belirtmek için bir billboard da ekliyoruz.
Ayrıca fare imlecinide gizlemek gerekiyor.
// disable mouse cursor
device->getCursorControl()->setVisible(false);
// add billboard
scene::IBillboardSceneNode * bill = smgr->addBillboardSceneNode();
bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR );
bill->setMaterialTexture(0, driver->getTexture( "../../media/particle.bmp"));
bill->setMaterialFlag(video::EMF_LIGHTING, false);
bill->setSize(core::dimension2d<f32>(20.0f, 20.0f));
// add 3 animated faeries.
video::SMaterial material;
material.Texture1 = driver->getTexture( "../../media/faerie2.bmp");
material.Lighting = true;
scene::IAnimatedMeshSceneNode* node = 0;
scene::IAnimatedMesh* faerie = smgr->getMesh( "../../media/faerie.md2");
if (faerie)
{
node = smgr->addAnimatedMeshSceneNode(faerie);
node->setPosition(core::vector3df(-70,0,-90));
node->setMD2Animation(scene::EMAT_RUN);
node->getMaterial(0) = material;
node = smgr->addAnimatedMeshSceneNode(faerie);
node->setPosition(core::vector3df(-70,0,-30));
node->setMD2Animation(scene::EMAT_SALUTE);
node->getMaterial(0) = material;
node = smgr->addAnimatedMeshSceneNode(faerie);
node->setPosition(core::vector3df(-70,0,-60));
node->setMD2Animation(scene::EMAT_JUMP);
node->getMaterial(0) = material;
}
material.Texture1 = 0;
material.Lighting = false;
// Add a light
smgr->addLightSceneNode(0, core::vector3df(-60,100,400),
video::SColorf(1.0f,1.0f,1.0f,1.0f),
600.0f); |
Kodu karışıklaştırmamak için seçme işlemini çizim döngüsünde yapıyoruz.
Şu an seçili olan ve son seçilen nesneleri belirten 2 adet gösterici tanımlayıp döngüye giriyoruz.
.
scene::ISceneNode* selectedSceneNode = 0;
scene::ISceneNode* lastSelectedSceneNode = 0;
int lastFPS = -1;
while(device->run()) if (device->isWindowActive())
{
driver->beginScene(true, true, 0);
smgr->drawAll(); |
"smgr->drawAll()" ile tüm sahneyi çizdirdikten sonra, ilk seçme işlemini yapacağız
: Sahnede hangi üçgene doğru baktığımızı bilmemiz gerekiyor. Bunun dışında q3 haritasında tam olarak hangi noktaya
baktığımızı da bilmemiz lazım.Bunun için kameranın olduğu pozisyondan başlayan ve bakış yönünde
giden 3 boyutlu bir doğru oluşturuyoruz.Bundan sonra "collision manager" nesnesine bu doğrunun
üçgen seçicinin içerdiği üçgenlerden biriyle kesişip kesişmediğini soruyoruz.Eğer kesişme var ise
üçgeni çizip, billboard nesnesini kesişme noktasına yerleştiriyoruz.
core::line3d<f32> line;
line.start = camera->getPosition();
line.end = line.start +
(camera->getTarget() - line.start).normalize() * 1000.0f;
core::vector3df intersection;
core::triangle3df tri;
if (smgr->getSceneCollisionManager()->getCollisionPoint(
line, selector, intersection, tri))
{
bill->setPosition(intersection);
driver->setTransform(video::ETS_WORLD, core::matrix4());
driver->setMaterial(material);
driver->draw3DTriangle(tri, video::SColor(0,255,0,0));
} |
Irrlicht motorunun desteklediği bir başka çarpışma testi tipi de sarmal kutu(bounding boxes)'lara dayanan
"SceneNode Picking". Her SceneNode'un bir sarmal kutusu vardır.Bu sebeple kameranın hedefinde bir nesne olup olmadığını
belirleme işlemi oldukça hızlıdır.Aynı şekilde yine "collision manager" nesnesine bunu soruyoruz.
Eğer kesişim var ise seçili nesneyi bir ışık ile belirginleştiriyoruz(Burada aslında ışık sabit, biz modelin
materyalini modifiye ediyoruz).
selectedSceneNode = smgr->getSceneCollisionManager()->
getSceneNodeFromCameraBB(camera);
if (lastSelectedSceneNode)
lastSelectedSceneNode->setMaterialFlag(
video::EMF_LIGHTING, true);
if (selectedSceneNode == q3node ||
selectedSceneNode == bill)
selectedSceneNode = 0;
if (selectedSceneNode)
selectedSceneNode->setMaterialFlag(
video::EMF_LIGHTING, false);
lastSelectedSceneNode = selectedSceneNode; |
Hepsi bu kadar,sadece çizim işlemini tamamlıyoruz.
driver->endScene();
int fps = driver->getFPS();
if (lastFPS != fps)
{
core::stringw str = L"Collision detection example - Irrlicht Engine ["; str += driver->getName(); str += "] FPS:"; str += fps;
device->setWindowCaption(str.c_str()); lastFPS = fps; }
}
device->drop();
return 0;
}
|
|