lunes, 16 de junio de 2008

Segundo tutorial: el HolaMundo más simple de Irrlicht (2ª parte)

Seguimos con el segundo tutorial ampliando ligeramente la versión del HolaMundo realizada en la primera parte, sin correr demasiado para ir asimilando bien las bases de Irrlicht.


De nuevo, los fuentes y el binario ya compilado están en el box: tutorial_02.zip.

El código sin comentarios quedaría tal que así:

#include <irrlicht/irrlicht.h>

using namespace irr;

using namespace core;
using namespace scene;
using namespace video;

int main()
{
/** INICIALIZACION **/

IrrlichtDevice *device = createDevice(
video::EDT_OPENGL, dimension2d(640, 480), 16,
false, false, false, NULL );

IVideoDriver* driver = device->getVideoDriver();
ISceneManager* smgr = device->getSceneManager();

/** CREACION **/

ICameraSceneNode* cameraNode = smgr->addCameraSceneNodeFPS( 0, 100.0f, 200.0f );

IMesh* boxMesh = smgr->getMesh( "res/box.x" );
IMeshSceneNode* boxNode = smgr->addMeshSceneNode( boxMesh );
boxMesh->drop();

/** ACTUALIZACION **/

boxNode->setScale( vector3d(10.0f,10.0f,10.0f) );
cameraNode->setPosition( vector3df(20,30,-40) );
cameraNode->setTarget( vector3df(0,5,0) );

/** EJECUCION **/

while( device->run() )
{
driver->beginScene( true, true, SColor(255,100,101,140) );
smgr->drawAll();
driver->endScene();
}

/** FINALIZACION **/

device->drop();
return 0;
}


Un primer cambio es apreciable en la cámara. El SceneManager de Irrlicht contiene un par de cámaras más sofisticadas que la utilizada en el primer tutorial. Estas cámaras destacan principalmente por venir pre-configuradas con eventos de teclado y ratón asociadas a ellas permitiendo manipularlas de forma intuitiva sin ninguna línea de código adicional. Las cámaras son llamadas "FPS" y "Maya". Si eres un jugón o te gusta el diseño gráfico ya te estarás imaginando el tipo de cámaras de las que hablamos.
La cámara FPS imita la configuración de la cámara típica de un Shooter (First Person Shooter) asociando los cursores a un movimiento de traslación horizontal y el ratón a la rotación de la cámara. Eso si, no esperes ningún tipo de colisión por defecto, ni siquiera con el plano horizontal XZ (el "suelo"), imagina más bien la configuración de cámara de un observador del shooter que está en "modo vuelo".
La cámara de tipo Maya tiene una configuración típica de un editor 3D, en el que la pulsación de los distintos botones del ratón y el movimiento del mismo activan las distintas opciones de: traslación, rotación y escalado/zoom de la cámara.
Ambas cámaras aceptan los mismos parámetros, y que interesen hasta el momento son el segundo y el tercero: velocidad de rotación y velocidad de traslación respectivamente.

Pero el verdadero cambio llega en las siguientes instrucciones. En este tutorial no vamos a pintar nosotros la caja explícitamente, en lugar de eso hemos abierto el Blender y la caja que aparece por defecto ha sido exportada a un formato que entienda Irrlicht, como por ejemplo DirectX (ficheros .x en texto plano). En cualquier aplicación gráfica que hagamos vamos a echar mano de modelos pre-diseñados, así que es el momento de enfocar el tutorial en ellos. El primer paso es realizar la carga del modelo y para ello se utiliza el método getMesh del SceneManager que es el encargado de generar una malla de Irrlicht a partir de un objeto almacenado en un archivo. Como se puede observar, tan solo se le proporciona como parámetro el modelo deseado, e Irrlicht internamente utiliza el cargador específico del formato en función de la extensión del fichero. Si le pasáramos una extensión que desconoce o sufriera algún tipo de error en la carga nos los indicará por la salida de consola.
Con nuestro modelo en forma de "Mesh", es el momento de añadirlo a nuestra escena de la misma forma que añadimos la cámara a traves del SceneManager. Hecho esto, la malla ya no la necesitamos y podemos hacer "drop" sobre ella. A partir de ahora, nuestra caja está encapsulada en un objeto llamado "MeshSceneNode" que nos va a proporcionar métodos para su manipulación, lo cual va a ser una gran ventaja comparado al tutorial anterior en el que la caja no la teníamos empaquetada de ninguna forma y nos dedicábamos a re-crearla en tiempo de render. ¿Porqué eso de "SceneNode"? El concepto de "nodo" en Irrlicht es la piedra angular de todo el engine. Ya comentábamos que el elemento SceneManager era la raíz de toda nuestra escena, pues bien, esto hay que tomárselo al pie de la letra ya que la escena está internamente representada en forma de árbol lógico con lo que nuestro SceneManager es literalmente la raíz del árbol. Partiendo de esta idea, es obvio entender como todo aquello que sea añadido a la escena es de forma genérica un nodo o "SceneNode". Iremos poco a poco descubriendo distintas implementaciones de nodos que extienden el SceneNode genérico para tratar con objetos más específicos, como por ejemplo los vistos hasta ahora: CameraSceneNode y MeshSceneNode.

En las últimas nuevas líneas de este tutorial podemos observar como realizar operaciones simples sobre nuestros objetos puestos en escena (la cámara y la caja). A través del puntero al nodo que hemos conservado se ha ajustado el escalado de la caja y la posición y enfoque de la cámara. Y lo mejor de todo, la tarea de render es poco más que un "drawAll" de nuestro gestor de escena.

Para concluir el tutorial, comentar que lo que ha sucedido internamente (respecto al tutorial 1) es que el pintado de la caja ha sido abstraído dentro del SceneNode, ya que es uno de sus método el encargado de acceder al VideoDriver para pintar la caja de forma similar a como lo hicimos en el tutorial anterior, y éste método es invocado automáticamente a través del "drawAll". Con lo cual, si estas pensando en hacer pintadas de forma manual a bajo nivel utilizando directamente el VideoDriver, te interesa implementarte tu propio SceneNode: tan sencillo como heredar de la interfaz "ISceneNode" e implementar sus métodos. Así integrarás limpiamente tu aplicación con Irrlicht.

No hay comentarios: