sábado, 23 de agosto de 2008

Tutorial 1


Este numero del tutorial ha sido tomado de: Lobo Tuerto

Todo proyecto comienza por un principio —ya sé, bonito aforismo. :P

Por fin haremos algo divertido —uy si, cuánto— con Irrlicht: vamos a agregar algunos objetos a nuestro espacio 3D y los mostraremos en pantalla. :)

Véanlo como poner a un actor en escena, es el primer paso para lograr una obra, en nuestro caso ¡un videojuego!

Los videojuegos en su parte más fundamental están compuestos por entidades, ya saben, siempre nos referimos a ellas como el personaje principal (o monito), los monstruos, las balas, las pociones, el castillo, etc.

Nosotros comenzaremos agregando cubos a nuestra aplicación, esperando que en un futuro no muy lejano se conviertan en temibles criaturas a las cuales podamos derrotar a base de espadazos o balazos —o algo así.

Objetivo

En este tutorial aprenderemos a agregar nodos de escena y a modificarles las siguientes propiedades:

  • Posición
  • Escala
  • Rotación

Pero, ¿qué es un nodo de escena?

Puesto de manera sencilla, los nodos de escena son entidades que pueden ser dibujadas en pantalla, pero en realidad pueden ser mucho más. Para el propósito de este tutorial nos quedaremos con la definición sencilla.

Debido a que vamos a estar moviendo y posicionando objetos en el espacio, debemos entender bien lo que son los sistemas de coordenadas y como los maneja Irrlicht.


El sistema de coordenadas de Irrlicht

Es importante comprender como funcionan las coordenadas dentro de Irrlicht, ya que nos servirán para posicionar de manera precisa los objetos donde queramos.

El espacio 3D

3d-coordinates.png

La explicación es sencilla.

Un punto en el espacio 3D está definido por 3 coordenadas (X,Y,Z).

El origen está definido por (0,0,0).

Para ubicarnos y entender esto, imagina que estás parado en (0,0,0) tu nariz apunta hacia el eje Z positivo (profundidad), hacia arriba esta el eje Y positivo (altura) y hacia tu derecha está el eje X positivo (anchura).

Así tenemos que:

  • X va de izquierda (-) a derecha (+).
  • Y va de abajo (-) hacia arriba (+).
  • Z va de atrás (-) hacia adelante (+).



Agregar un nodo de escena

Comenzaremos con un programa mínimo para hacer experimentos.

  1. #include
  2. using namespace irr;
  3. using namespace core;
  4. using namespace scene;
  5. using namespace video;
  6. using namespace io;
  7. using namespace gui;
  8. int main() {
  9. // Inicializamos Irrlicht
  10. IrrlichtDevice *device = createDevice(EDT_OPENGL, dimension2d (800, 600), 32, false, false, false, 0);
  11. // Guardamos los apuntadores que serán de utilidad
  12. IVideoDriver* driver = device->getVideoDriver();
  13. ISceneManager* smgr = device->getSceneManager();
  14. IGUIEnvironment* guienv = device->getGUIEnvironment();
  15. // Le ponemos un título a nuestra ventana
  16. wchar_t title[1024];
  17. swprintf(title, 1024, L"Tutorial Irrlicht #3 | Lobo tuerto [%S]", driver->getName());
  18. device->setWindowCaption(title);
  19. // El ciclo principal de nuestra aplicación
  20. while (device->run()) {
  21. driver->beginScene(true, true, SColor(255, 217, 194, 140));
  22. smgr->drawAll();
  23. driver->endScene();
  24. }
  25. // Nos aseguramos de cerrar de manera adecuada Irrlicht
  26. device->drop();
  27. // Siempre es bueno regresar un cero para indicar que todo salió bien
  28. return 0;
  29. }



Bien, ahora llamaremos a nuestro primer actor a escena: un cubo.


  1. smgr->addCubeSceneNode();

Esa línea de código agrega un cubo a nuestra escena en las coordenadas (0,0,0).

Si queremos colocarlo en otra posición es necesario guardar un apuntador a él para poder cambiar sus propiedades a placer.

Así que mejor escribimos algo como esto:


  1. ISceneNode* cube = smgr->addCubeSceneNode();

Ya tenemos nuestro actor, ahora necesitamos una cámara para poder verlo:


smgr->addCameraSceneNode(0, vector3df(0, 30, -40), vector3df(0, 0, 0));


Agrega esas dos últimas líneas de código antes de que inicie el ciclo principal de la aplicación.



Analizando a addCameraSceneNode

Creo que es necesario explicar un poco el uso de vectores dentro de Irrlicht.

La forma de definir un vector de 3 coordenadas en Irrlicht es con la clase vector3df —que en realidad es un typedef de un template.

Al crearse, las instancias de esta clase reciben 3 números flotantes que representan las coordenadas X, Y y Z. Como ejemplo, crearemos el vector A:


  1. vector3df A(10.3,5,8.2);

Si quisieramos leer la coordenada X lo hacemos con:


  1. A.X;

Y para modificar la coordenada Y con:


  1. A.Y = 10.5;

El método addCameraSceneNode recibió 3 parámetros:

  • 0parent, nodo de escena padre de la cámara, puede ser nulo. Si el padre se mueve, la cámara se mueve con él.
  • vector3df(0, 30, -40)position, la posición en el espacio relativa al padre donde será colocada la cámara. Si no hay un padre, se toma el origen (0,0,0) como referencia.
  • vector3df(0, 0, 0)lookat, posición hacia donde mirará la cámará. También se le conoce como target (objetivo).

irrlicht-tutorial-3-1.png

Entonces, ¿qué fue lo que hicimos con la cámara?

Pues, “caminamos” hacia atrás 40 unidades (desplazamiento negativo en Z), “subimos” 30 (desplazamiento positivo en Y) y finalmente “miramos” hacia el origen —que es ahí donde reside nuestro cubo.

Creo que es un buen momento para probar nuestro programa y maravillarnos ante el cubo negro que aparece contra un fondo color arena. :D


Modificar las propiedades de un nodo de escena

Ahora le daremos algunas instrucciones a nuestro actor, como colocarse en cierto lugar, girar y cambiar de tamaño.

Estas indicaciones se las podemos dar con:

  • setPosition(vector3df(X,Y,Z)).
  • setScale(vector3df(X,Y,Z)).
  • setRotation(vector3df(X,Y,Z)).

¿Cómo pondríamos al cubo 5 unidades delante de la posición inicial (0,0,0)?


  1. cube->setPosition(vector3df(0,0,5));

La sintáxis para setScale y setRotation es exactamente la misma que para setPosition. Así, la siguiente línea de código convertiría al cubo en un prisma rectangular, escalado a lo largo del eje X (a lo ancho) cinco veces:


  1. cube->setScale(vector3df(5,1,1));

Ahora es un buen momento para practicar un poco lo aprendido sobre posición, rotación y escala. Juega un rato con esos métodos hasta que te sientas cómodo con el sistema de coordenadas de Irrlicht.

A veces es bueno despejar un poco la mente para que los nuevos conocimientos permeen nuestra cabeza.

Y para despejar la mente nada como un delicioso café, jeje. :P

Los nodos de escena tienen otros tres métodos básicos:

  • getPosition()
  • getRotation()
  • getScale()

Los tres métodos regresan un vector3df.

¿De qué manera útil podríamos ocupar estos métodos?
Digamos que quieres mover el cubo 12 unidades a la derecha de su posición actual, eso se logra con:


  1. cube->setPosition(cube->getPosition() + vector3df(12,0,0));

Recuerda que el término derecha es relativo.

Éste es correcto para la posición y orientación de la cámara que estamos usando en este tutorial, pero si la cambias de posición, puede que el eje X positivo ya no siga siendo la derecha.

Pero no hay tanto problema, solo debes pensar en terminos de coordenadas 3D. :)


Otra pregunta, ¿cómo quedaría el programa si quisieras dejar girando en pantalla al prisma rectangular?
Piénsale un ratito y después échale un ojo al código de abajo.


  1. #include
  2. using namespace irr;
  3. using namespace core;
  4. using namespace scene;
  5. using namespace video;
  6. using namespace io;
  7. using namespace gui;
  8. int main() {
  9. // Inicializamos Irrlicht
  10. IrrlichtDevice *device = createDevice(EDT_OPENGL, dimension2d (800, 600), 32, false, false, false, 0);
  11. // Guardamos los apuntadores que serán de utilidad
  12. IVideoDriver* driver = device->getVideoDriver();
  13. ISceneManager* smgr = device->getSceneManager();
  14. IGUIEnvironment* guienv = device->getGUIEnvironment();
  15. // Le ponemos un título a nuestra ventana
  16. wchar_t title[1024];
  17. swprintf(title, 1024, L"Tutorial Irrlicht #3 | Lobo tuerto [%S]", driver->getName());
  18. device->setWindowCaption(title);
  19. ISceneNode* cube = smgr->addCubeSceneNode();
  20. cube->setScale(vector3df(5,1,1));
  21. smgr->addCameraSceneNode(0, vector3df(0, 30, -40), vector3df(0, 0, 0));
  22. // El ciclo principal de nuestra aplicación
  23. while (device->run()) {
  24. // En cada ciclo hacemos rotar al prisma 0.05 grados sobre su eje Z.
  25. cube->setRotation(cube->getRotation()+vector3df(0,0,0.05));
  26. driver->beginScene(true, true, SColor(255, 217, 194, 140));
  27. smgr->drawAll();
  28. driver->endScene();
  29. }
  30. // Nos aseguramos de cerrar de manera adecuada Irrlicht
  31. device->drop();
  32. // Siempre es bueno regresar un cero para indicar que todo salió bien
  33. return 0;
  34. }

Prueba haciéndolo girar sobre otros ejes, incluso sobre dos al mismo tiempo.

Asígnale un número negativo al ángulo para hacer que gire en sentido contrario.


Entendiendo las rotaciones en Irrlicht

Los valores que recibe setRotation son grados, y van de 0 a 360 (como en el círculo).

irrlicht-tutorial-3-objetivo.png

¿Sabes porque el prisma gira en el sentido en el que lo hace?
La razón es que Irrlicht utiliza el sistema de coordenadas de mano izquierda. Imagina que estás parado en la posición (0,0,0) mirando al frente hacia el eje Z positivo. Ahora con la palma abierta de tu mano izquierda, alínea tu pulgar con este eje (hacia el frente, tu palma quedará hacia arriba) ahora cierra la palma de tu mano y deja tu pulgar extendido.

La dirección en la que se enrollan tus dedos es la dirección en la que gira el prisma rectangular.

Haz el experimento también con el eje X y el eje Y (apunta tu pulgar en la dirección positiva de estos ejes y fíjate hacia donde se enrollan tus dedos) y verifica que lo que estás leyendo es cierto. :D


Bueno, para los que se preguntaban para que sirven las matemáticas que te dan en la prepa y en la uni, espero ya se hayan comenzado a dar cuenta. :)




No hay comentarios: