Introducción a Irrlicht
Transcripción
Introducción a Irrlicht
VIDEOJUEGOS 2 Introducción a Irrlicht V2 Introducción a Irrlicht Motor Irrlicht • Motor gráfico 3D Open Source • Escrito en C++ • Licencia zlib/libpng • No obliga a mencionar que estamos utilizando Irrlicht • Multiplataforma • Windows, Linux, MacOS • Renderers • OpenGL, Direct 3D, Software • No es un motor de juego, pero nos proporciona ayudas • Detección de colisiones • Control mediante ratón / joystick / teclado • Cámara para FPSs Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 2 V2 Introducción a Irrlicht Instalación de Irrlicht • Descargamos el SDK 1.8 de Irrlicht http://irrlicht.sourceforge.net • Descomprimimos el fichero y veremos Ejecutables de los ejemplos Ejemplos de uso de Irrlicht Configurar como directorio de headers Librerías compiladas (sólo precompiladas para Windows) Código fuente de la librería. En Linux y MacOS es necesario recompilarla Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 3 V2 Introducción a Irrlicht Compilación de Irrlicht en Linux • Desde ${IRRLICHT}/source/Irrlicht ejecutamos • make (configuración debug) • make NDEBUG=1 (configuración release) • Es necesario contar previamente con las librerías • • • • Xxf86vm GL Xext Xcursor sudo apt-‐get install build-‐essential libxxf86vm-‐dev mesa-‐common-‐dev libgl1-‐mesa-‐dev libglu1-‐mesa-‐dev libxext-‐dev libxcursor-‐dev Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 4 V2 Introducción a Irrlicht Compilación de Irrlicht en MacOS • En ${IRRLICHT}/source/Irrlicht/MacOSX hay un proyecto Xcode • Lo abrimos y compilamos con Xcode el target libIrrlicht.a • Xcode 4.X • Debemos cambiar en Build Settings el compilador a GCC • Xcode 5.X • Ya no soporta compilador GCC. Deberemos: • En COpenGLExtensionHandler.h cambiar (long GLuint) por: glProgramParameteriEXT((GLuint)(uintptr_t)program, pname, value); • En ClrrDeviceMacOSX.h encerrar en un bloque ifndef: #ifndef __OBJC__ class NSWindow; class NSOpenGLContext; class NSBitmapImageRep; #endif Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 5 V2 Introducción a Irrlicht Compilación de nuestro proyecto • Linux g++ -‐I${IRRLICHT}/include -‐I/usr/X11R6/include -‐O3 -‐ffast-‐math main.cpp -‐o main -‐L/usr/X11R6/lib -‐L${IRRLICHT}/lib/Linux -‐lIrrlicht -‐lGL -‐lXxf86vm -‐lXext -‐lX11 -‐lXcursor • MacOS g++ main.cpp -‐o main -‐arch i386 -‐I${IRRLICHT}/include -‐L${IRRLICHT}/source/Irrlicht/MacOSX/build/Release -‐lIrrlicht -‐framework OpenGL -‐framework Cocoa -‐framework Carbon -‐framework IOKit Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 6 V2 Introducción a Irrlicht Crear proyecto con Visual Studio • Crear nuevo proyecto de tipo • Visual C++ > Aplicación de consola Win32 • En el asistente de configuración marcar “Proyecto vacío” • Entrar en Proyecto > Propiedades • Doble click en Propiedades de configuración para desplegarlo • Seleccionar Directorios VC++ • Añadir como directorio de inclusión ${IRRLICHT}/include • Añadir como directorio de bibliotecas ${IRRLICHT}/lib/Win32-‐visualstudio • Añadir un nuevo fichero fuente de tipo Archivo C++ IMPORTANTE: Copiar Irrlicht.dll (de ${IRRLICHT}/bin/Win32-‐ visualstudio) al directorio donde vayan a estar nuestros ejecutables Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 7 V2 Introducción a Irrlicht Estructura de la librería • Debemos importar irrlicht.h #include <irrlicht.h> • El espacio de nombres principal es irr using namespace irr; Propósito general • Encontramos 5 módulos using using using using using namespace namespace namespace namespace namespace core; scene; video; io; gui; Escena 3D Driver y rendering Ficheros Interfaz de usuario Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 8 V2 Introducción a Irrlicht Irrlicht device • Es el objeto principal que nos permitirá interactuar con el motor • Hace de interfaz con el hardware gráfico int main() Renderer Tamaño ventana Profundidad { IrrlichtDevice *device = createDevice(video::EDT_SOFTWARE, dimension2d<u32>(640, 480), 16, false, false, false, 0); if (!device) return 1; color Fullscreen // Ciclo del juego // ... device->drop(); return 0; } Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 9 V2 Introducción a Irrlicht Ciclo del juego • Irrlicht proporciona facilidades para crear el ciclo del juego • Necesitamos un objeto video driver para realizar el render • Podemos obtenerlo a partir del device • Se utiliza doble buffer para evitar flickering IVideoDriver* driver = device->getVideoDriver(); while(device->run()) { driver->beginScene(true, true, SColor(255,100,101,140)); // Dibujar contenido // ... driver->endScene(); } Intercambia buffers Videojuegos II Inicializa back buffer. Se indica si vaciar back buffer y Z-buffer © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 10 V2 Introducción a Irrlicht Interfaz de usuario • Útil para definir menús y HUD • Obtenemos el entorno GUI con IGUIEnvironment* guienv = device->getGUIEnvironment(); • Podemos añadir distintos elementos al GUI • • • • Texto Imágenes Controles Sprites guienv->addStaticText(L"Hola mundo!", rect<s32>(10,10,260,22)); • Dibujamos contenido del GUI dentro del ciclo del juego con guienv->drawAll(); Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 11 V2 Introducción a Irrlicht Grafo de la escena Escena Cámara Transformación Transformación Maya 3D Videojuegos II Transformación Transformación Maya 3D Luz Maya 3D Luz Maya 3D © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 12 V2 Introducción a Irrlicht Gestión de la escena • Toda la escena se gestiona mediante el objeto ISceneManager • Se obtiene a través del device ISceneManager* smgr = device->getSceneManager(); • Permite • • • • Crear nodos para introducir en el grafo Modificar los nodos que forman el grafo Cargar diferentes formatos de mayas 3D Crear geometría 3D básica • Dibujar toda la escena en el ciclo del juego smgr->drawAll(); Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 13 V2 Introducción a Irrlicht Ciclo del juego completo int main() { IrrlichtDevice *device = createDevice(video::EDT_SOFTWARE, dimension2d<u32>(640, 480), 16, false, false, false, 0); if (!device) return 1; IVideoDriver* driver = device-‐>getVideoDriver(); ISceneManager* smgr = device-‐>getSceneManager(); IGUIEnvironment* guienv = device-‐>getGUIEnvironment(); while(device-‐>run()) { driver-‐>beginScene(true, true, SColor(255,100,101,140)); smgr-‐>drawAll(); guienv-‐>drawAll(); driver-‐>endScene(); } device-‐>drop(); return 0; } Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 14 V2 Introducción a Irrlicht Nodos del grafo • Los nodos del grafo son objetos que heredan de ISceneNode • Tienen una posición relativa respecto al nodo padre • Existen nodos de distintos tipos • • • • • ICameraSceneNode ILightSceneNode IMeshSceneNode IDummyTransformationSceneNode ITextSceneNode • Todos los tipos de nodos nos permiten cambiar su posición • setPosition / getPosition • setRotation / getRotation Utilizan el tipo vector3df • setScale / getScale Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 15 V2 Introducción a Irrlicht Cámara • Un nodo imprescindible es la cámara • Puede haber varias cámaras en el grafo, pero sólo una activa • Añadimos este nodo a la escena con: Posición smgr->addCameraSceneNode(0,vector3df(0,30,-40), vector3df(0,5,0)); Dirección Nodo padre (con 0 cuelga del nodo raíz) • Podemos cambiar la cámara activa con: smgr->setActiveCamera(camera); Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 16 V2 Introducción a Irrlicht Mayas 3D • Objetos que implementan la interfaz IMesh • Podemos cargarlos de un fichero o crear geometría básica IMesh* mesh = smgr->getMesh("maya.obj"); if (!mesh) { device->drop(); return 1; } • Creamos un nodo en el grafo a partir de la maya IMeshSceneNode *nodo = smgr->addMeshSceneNode(mesh); • Podemos desactivar iluminación para pruebas iniciales if(nodo) { nodo->setMaterialFlag(EMF_LIGHTING, false); } Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 17 V2 Introducción a Irrlicht Geometría básica • Para el prototipo inicial del videojuego no hace falta modelar • Podemos utilizar geometría básica para los elementos del juego • El objeto IGeometryCreator permite crear estas mayas básicas • Se obtiene a partir del scene manager • Podemos crear diferentes tipos de mayas de forma sencilla IMesh *cube = smgr->getGeometryCreator() ->createCubeMesh(vector3df(5.f, 5.f, 5.f)); • Existen atajos directos desde scene manager IMeshSceneNode *cubeNode = smgr->addCubeSceneNode(5.f); Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 18 V2 Introducción a Irrlicht Manipulación de la maya • Podemos cambiar propiedades de una maya • Utilizamos para ello el objeto mesh manipulator • Este objeto se obtiene a partir del scene manager smgr->getMeshManipulator() • Por ejemplo, podemos hacer que el cubo anterior sea rojo smgr->getMeshManipulator() ->setVertexColors(cubeNode->getMesh(), SColor(255, 255, 0, 0)); Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 19 V2 Introducción a Irrlicht Transformaciones • Podemos aplicar transformaciones a conjuntos de nodos • Por ejemplo, agrupar una luz y una maya con forma de coche bajo un mismo nodo, y así mover el coche y su faro de forma conjunta • El nodo IDummyTransformationSceneNode nos permite esto IDummyTransformationSceneNode *group = smgr->addDummyTransformationSceneNode(); • Las transformaciones siempre se aplican a su matriz 4x4 group->getRelativeTransformationMatrix() .setTranslation(vector3d<float>(0, 0, 20)); • Podemos añadir hijos a este nodo IMeshSceneNode *sceneNode = smgr->addCubeSceneNode(10, group); Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 20 V2 Introducción a Irrlicht Gestión de la memoria • Irrlicht funciona mediante cuenta de referencias • Al crear un objeto con un método create* tenemos una referencia • grab() incrementa el contador • drop() lo decrementa, al llegar a cero se liberará la memoria • Recomendación: Dejar que Irrlicht gestione la memoria • Al añadir un nodo al grafo de la escena éste lo retiene • Al eliminarlo con remove() se libera la referencia • Esto se aplica a cualquier otra estructura a la que se añada el objeto • Seremos responsables de llamar a drop() únicamente para los objetos creados con create(). Podemos llamar a drop() una vez alguna estructura los haya retenido. ISceneNodeAnimator *animator = smgr->createRotationAnimator(vector3df(1,1,1)); cubeNode->addAnimator(animator); // Lo retiene animator->drop(); Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 21 V2 Introducción a Irrlicht Cachés de objetos • Irrlicht mantiene una serie de cachés • Optimiza la carga de mayas y texturas • Caché de mayas • Objeto IMeshCache accesible con smgr->getMeshCache() • Cuando cargamos una maya con getMesh() se guarda aquí • Podemos vaciarla con clear()o eliminar una con removeMesh() • Caché de texturas • Gestionada por IVideoDriver • Todas las texturas cargadas se guardan aquí, evita duplicidades • Se puede vaciar con removeAllTextures() o eliminar una textura concreta con remoteTexture() • Es importante asegurarse de que las texturas no se estén utilizando Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 22 Introducción a Irrlicht V2 Ejemplo completo int main() { IrrlichtDevice *device = createDevice(video::EDT_OPENGL, dimension2d<u32>(640, 480), 16, false, false, false, 0); if (!device) return 1; IVideoDriver* driver = device->getVideoDriver(); ISceneManager* smgr = device->getSceneManager(); IGUIEnvironment* guienv = device->getGUIEnvironment(); IMeshSceneNode *cubeNode = smgr->addCubeSceneNode(10); if(cubeNode) { cubeNode->setMaterialFlag(EMF_LIGHTING, false); cubeNode->setPosition(vector3df(0,10,0)); } smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0)); while(device->run()) { driver->beginScene(true, true, SColor(255,100,101,140)); smgr->drawAll(); guienv->drawAll(); driver->endScene(); } device->drop(); return 0; } Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 23 V2 Introducción a Irrlicht Eventos de teclado • Debemos definir un receptor de eventos propio • Clase que hereda de IEventReceiver class CAppReceiver : public IEventReceiver • El receptor se registra en el device al crearlo CAppReceiver appReceiver; IrrlichtDevice *device = createDevice(video::EDT_OPENGL, dimension2d<u32>(640, 480), 16, false, false, false, &appReceiver); • El receptor guardará la información de las teclas pulsadas • En el ciclo del juego comprobamos mediante el receptor las teclas pulsadas Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 24 V2 Introducción a Irrlicht Receptor de eventos class CAppReceiver : public IEventReceiver { private: bool KeyDown[KEY_KEY_CODES_COUNT]; public: CAppReceiver() { for(int i=0;i<KEY_KEY_CODES_COUNT;i++) { KeyDown[i] = false; } } virtual bool OnEvent(const SEvent &event) { switch(event.EventType) { case irr::EET_KEY_INPUT_EVENT: { KeyDown[event.KeyInput.Key] = event.KeyInput.PressedDown; } default: break; } return false; } virtual bool isKeyDown(EKEY_CODE keyCode) const { return KeyDown[keyCode]; } virtual bool isKeyUp(EKEY_CODE keyCode) const { return !KeyDown[keyCode]; } }; Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 25 V2 Introducción a Irrlicht Entrada en el ciclo del juego while(device->run()) { if(device->isWindowActive()) { vector3df cubePos = cubeNode->getPosition(); if(appReceiver.isKeyDown(KEY_ESCAPE)) { device->closeDevice(); return 0; } else if(appReceiver.isKeyDown(KEY_RIGHT)) { cubePos.X += 0.1; } else if(appReceiver.isKeyDown(KEY_LEFT)) { cubePos.X -= 0.1; } cubeNode->setPosition(cubePos); Entrada driver->beginScene(true, true, SColor(255,100,101,140)); smgr->drawAll(); guienv->drawAll(); Render driver->endScene(); } else { device->yield(); } } Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 26 V2 Introducción a Irrlicht Delta time • Para conseguir una velocidad constante debemos conocer el incremento de tiempo de cada fotograma (delta time) • Podemos calcularlo de la siguiente forma u32 then = device->getTimer()->getTime(); while (device->run()) { if (device->isWindowActive()) { const u32 now = device->getTimer()->getTime(); const f32 dt = (f32) (now - then) / 1000.f; // Actualizar y dibujar escena en función de dt then = now; } else { device->yield(); } } Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 27 V2 Introducción a Irrlicht Animaciones • Podemos añadir animaciones a los nodos del grafo • Encontramos distintos tipos de animaciones • Todas ellas heredan de ISceneNodeAnimator Movimiento en círculo, línea recta, spline Rotación del objeto Animación de textura Eliminación Colisiones • Se crean a partir del scene manager y se añaden a los nodos ISceneNodeAnimator *animator = smgr->createRotationAnimator(vector3df(1.f,0.f,0.f)); cubeNode->addAnimator(animator); animator->drop(); Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 28 V2 Introducción a Irrlicht Detección de colisiones • Un tipo especial de animación es la de colisión • ISceneNodeAnimatorCollisionResponse • Necesita dos elementos • Geometría del mundo con la que colisionará (triangle selector) • Zona (elipsoide) de nuestro nodo que entrará en colisión • En primer lugar debemos crear el triangle selector del mundo ITriangleSelector *world = smgr->createTriangleSelector( escenario->getMesh(), escenario); escenario->setTriangleSelector(world); world->drop(); Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Maya de la que obtener la geometría Nodo en cuya posición se situa la maya Introducción a Irrlicht 29 V2 Introducción a Irrlicht Meta triangle selector • Si queremos comprobar colisiones con varios nodos podemos crear un meta triangle selector • Agrupa la geometría de varios nodos IMetaTriangleSelector *world = smgr->createMetaTriangleSelector(); ITriangleSelector *selector1 = smgr->createTriangleSelector(sceneNode1->getMesh(), sceneNode1); sceneNode1->setTriangleSelector(selector1); world->addTriangleSelector(selector1); selector1->drop(); ITriangleSelector *selector2 = smgr->createTriangleSelector(sceneNode2->getMesh(), sceneNode2); sceneNode2->setTriangleSelector(selector2); world->addTriangleSelector(selector2); selector2->drop(); Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 30 V2 Introducción a Irrlicht Animador de colisiones • Aplicamos animador de colisiones a uno de nuestros nodos ISceneNodeAnimator *anim = smgr->createCollisionResponseAnimator( escenario->getTriangleSelector(), cubeNode, vector3df(1.5,1.5,1.5), vector3df(0,-10,0), vector3df(0,0,0)); cubeNode->addAnimator(anim); anim->drop(); • El animador de colisiones permite • Aplicar gravedad • Conocer los datos de la colisión • Saltar (jump) Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Geometría del mundo Nodo en cuya posición comprueba colisiones Radio del elipsoide alrededor del centro de nuestro nodo Vector gravedad Desplazamiento del centro del elipsoide respecto al centro del nodo Introducción a Irrlicht 31 V2 Introducción a Irrlicht Cámara FPS • Se proporciona una cámara con comportamiento FPS • Implementa ya el control con teclado y ratón • Sólo tenemos que añadirla al grafo de la escena ICameraSceneNode *camera = smgr->addCameraSceneNodeFPS(); • Podemos añadirle un detector de colisiones con gravedad ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator( world, camera, vector3df(1,2,1), vector3df(0,-10,0), vector3df(0,2,0)); camera->addAnimator(anim); anim->drop(); Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 32 V2 Introducción a Irrlicht Trazado de rayos • Podemos también detectar colisiones mediante trazado de rayos • Útil para saber si estamos apuntando hacia un objeto • Es necesario que los nodos tengan un triangle selector asignado previamente para poder detectar la colisión con ellos ISceneCollisionManager* cm = smgr->getSceneCollisionManager(); vector3df intersection; triangle3df hitTriangle; ISceneNode * selectedSceneNode = cm->getSceneNodeAndCollisionPointFromRay( ray, Tipo Parámetros de intersection, line3d salida hitTriangle); Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 33 V2 Introducción a Irrlicht Referencias • Página web de Irrlicht • Tutoriales, ejemplos, referencia de la API, wiki • http://irrlicht.sourceforge.net • Irrlicht 1.7 Realtime 3D Engine Beginner's Guide • Johannes Stein, Aung Sithu Kyaw • Packt Publishing Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 34 V2 Introducción a Irrlicht ¿Preguntas...? Videojuegos II © 2014-2015 Depto. Ciencia de la Computación e IA Introducción a Irrlicht 35