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

Documentos relacionados