domingo, 11 de julio de 2010

Panda3D : ShowBase, The Scene Graph

En construcción...

lunes, 5 de julio de 2010

PANDA3D: Embebido en Web

Es este tuorial aprenderemos a colgar nuestras aplicaciones de Panda3d en la web.

Lo primero que tenemos es bajarnos el software openssl, es para crear nuestro certificado. Este no es mas que un fichero con los datos del autor, para dar mayor confianza a la hora de ejecutar dicho software.

Para crear un certificado (Ms-dos):

openssl genrsa 1024 > mycert.pem
 
 Para introducir los datos de tu creación y autor (Ms-dos):

openssl req -new -x509 -nodes -sha1 -days 365 -key mycert.pem >> mycert.pem
 
Con esteo tenemos el fichero mycert.pem, que nos valdrá, para todas las aplicaciones de panda3d que colguemos en la web.

Siguiendo los tutoriales anteriores, crearemos un proyecto o usaremos uno existente.

  • Primero que debemos hacer es crear la la raiz de nuestro proyecto un main.py, será por el que pregunte nuestro P3D, y despues tendremos la estructura de carpetas necesarias para arrancar la aplicaciones. Para las imagenes, videos, audio, modelos... la estructura de carpetas y nombres deben de ser iguales que en nuestro PANDA3D_HOME, si dentro hemos metido nuestras imagenes y modelos, los cogerá de ellos, si no lo hemos introducido arrancará con las imagenes del PANDA3D_HOME donde esté ubicado nuestro fichero P3D.

Ahora bien una vez echo la estructura:

Src-
    main.py
    img
    ...

Ejecutamos en siguiente comando:

packp3d -S mycert.pem -o myapp.p3d -d c:/src 
 
Con el certificado, esto nos creará un fichero lamado myapp.p3d, una vez echo esto abrimos cualquier editor y copiamos y pegamos el siguiente codigo:

<object width="640" height="480"
  type="application/x-panda3d" data="myapp.p3d">
</object>
 
Guardamos el editor y le ponemos el nombre que queramos .HTML, lo ejecutamos en un navegador y ¡¡¡¡WALAAAA!!!! tenemos nuestra aplicación corriendo en la web. A continuacion hemos creado un ejemplo, para ver como se ejecuta nuestra aplicación en la web.

(Si pareciera quedarse congelado el navegador de internet, cerrad la pestaña o la ventana y volved a acceder al blog, salvo IE que quizás necesitéis reiniciar el PC)

Controles:
  • Botón izquierdo del ratón: subir/bajar la vista, deslizar a izquierda/derecha la vista
  • Botón derecho del ratón: acercar/alejar la vista
  • Botón central del ratón (rueda): girar la vista
Para visualizar este ejemplo, debeis instalar el WebRuntime de Panda3D.












domingo, 20 de junio de 2010

PANDA3D: Modelos para ejemplos

Hemos creado un par de modelos muy simples y cutres (no somos modeladores :D) pero que cubrirán nuestras necesidades para los futuros tutoriales, ya que podremos ver cómo mover el coche sobre el escenario, las colisiones, la física, sonidos, luces, sombras, etc. Para los que tengan interés en seguir los tutoriales, subimos los modelos a Megaupload para que los puedan usar. Los archivos .egg debéis copiarlos a la carpeta models de Panda3D y los .tga en la carpeta maps dentro de models. Listo.



sábado, 19 de junio de 2010

PANDA3D: Exportar modelos desde Blender para usarlos en nuestro juego con Panda3D

Vamos a explicar cómo exportar correctamente desde Blender un modelo que creemos para poder utilizarlo en nuestro juego desarrollado en Panda3D. No voy a explicar cómo usar Blender ni cómo modelar en él, ya que se escapa del alcance del tutorial. Para ello podeis acudir a webs como:
o dando una vuelta por Google, ya que la comunidad es inmensa.

Partamos de la situación en la que tenemos un modelo y queremos añadirle una textura para que el exportador a Panda3D la reconozca correctamente (si no, no se verá la textura al cargar el modelo en nuestra aplicación). El exportador que utilizaremos se llama Chicken Exporter, y en su web podeis descargar la última versión del plugin para Blender.

Para instalar el plugin debéis buscar la carpeta .blender que este crea y es donde se encuentran los plugins y scripts de python que utiliza el mismo. Descomprimiremos lo que descarguemos de la web de Chicken Exporter y copiaremos las carpetas y los .py de su interior directamente en la carpeta scripts dentro de .blender, respondiendo afirmativamente si nos pregunta sobreescribir archivos.

Abrimos Blender y podemos verificar si está correctamente instalado el plugin accediendo a la ventana de Scripts y en el menú Scripts > Export debería de haber una opción llamada Chicken que exporta en .egg

Pasamos a abrir el modelo que queremos texturizar. Para los que sepan manejar Blende, lo que vamos a hacer es crear texturas UV (no se el nombre técnico), desdoblando las caras del modelo y luego con la plantilla de estas colocar la textura como queramos que se vea mediante un programa de manipulación de imágenes. Tras abrir el modelo lo tendremos en pantalla tal que así.


Añadimos una ventana donde visualizaremos la vista UV/Image editor. Tras esto, seleccionaremos el modelo con el botón derecho del ratón y pulsaremos TAB para entrar en modo edición. Pulsaremos la tecla A para seleccionar todos los vértices y aristas si no lo están ya y pulsamos la tecla U. En el menú que aparece seleccionamos Unwrap o Unwrap (smart projections) dependiendo de la complejidad de nuestra figura y de con cual opción dibuje mejor plantilla para luego crear la textura. Quedando una cosa así.


Ahora realizaremos un paso opcional que solo seguiremos si queremos crear una textura detallada de un modelo, por ejemplo si tenemos una puerta y queremos darle distintas texturas a cada parte de esta, los bordes, la puerta, el pomo, etc.

OPCIONAL: En la vista UV/Image editor nos dirigimos al menú UVs > Scripts > Save UV Face Layouts... y pulsamos OK en la ventana que se abre. Seleccionamos en el explorador dónde queremos guardar el fichero .tga que generará la plantilla para crear la textura con cada cara del modelo. Usaremos esta plantilla con un programa de edición de imágenes para crear la textura a nuestro gusto ya que al tener la plantilla, sabremos dónde debe de ir la textura del borde, de la puerta, el pomo, etc. (en el caso que fuera, por ejemplo, una puerta). Guardaremos la textura con la extensión que queramos.

Para cargar nuestra textura iremos al menú Image > Open... y buscaremos la imagen que queremos usar como textura (si seguimos el paso opcional, buscaremos esta imagen que al abrirse se verá debajo de la plantilla y podremos verificar que todo está en su sitio). Obteniendo como resultado algo así.



Ahora debemos decirle a Blender que utilice esa imagen como textura y que sea UV. Para ello salimos del modo edición pulsando en TAB de nuevo. Para acceder a las opciones de los materiales y texturas pulsamos la opción de Shading en el menú de botones teniendo el modelo seleccionado. Apareciendo algo así.



Pulsamos en Add New y nos creará un material para el modelo. Ahora vamos a la derecha del todo (para moverse si las opciones se salen de la pantalla, dejamos pulsado el botón central del ratón y lo movemos) y en la sección de Texture pulsamos en el botón Add new. Debemos indicarle a Blender (para que al exportarlo podamos modificar la ruta de las texturas) que debe tratar las texturas como UV. Para ello vamos a la pestaña Map Input y pulsamos la opción UV (junto a Orco). Ahora accedemos a las opciones de textura, que se vería así.



En Texture Type seleccionamos Image y nos aparecerán más opciones. A la derecha del todo está la opción Load. No la pulsamos, en su lugar le damos al botón con flechas que hay pegado a la izquierda de este botón y en la lista aparecerá la imagen que queremos usar como textura, la seleccionamos.

Pulsamos F12 para ver cómo ha quedado nuestro modelo texturizado.



Ahora procederemos a exportar el modelo. Para ello abrimos una ventana de Script y accedemos al menú Scripts > Export > Chicken (.egg)... Aparecerá una ventana como la siguiente.



Seleccionamos el modelo que queremos importar (botón derecho del ratón) y pulsamos en Update Selection, cada vez que seleccionemos un modelo distinto debemos pulsar ese botón. A continuación en Select indicaremos dónde se almacenará el archivo con el modelo en egg, en nuestro caso podemos ponerlo en la carpeta models de Panda3D. Pulsamos Export y esperamos hasta que nos indique de que esta ha terminado.


Esto nos generará un archivo .egg con nuestro modelo, este no es mas que un archivo de texto plano con los datos que usará Panda3D para mostrarnos este en el entorno 3D. Si lo intentáramos usar ahora mismo, seguramente obtendríamos una figura completamente blanca o si colocamos luces, gris. Esto es porque no está utilizando la textura que le indicamos en Blender, para ello accedemos a la carpeta donde hemos colocado el archivo .egg y lo editamos con cualquier editor de texto (aunque recomiendo Notepad++) y buscamos la etiqueta . Veremos que está indicando una ruta relativa que seguramente será incorrecta (si no lo es, no tocamos nada), algo como “./../../ruta/a/la/textura.png” donde ./ es la carpeta donde se encuentra el archivo .egg . Para solucionarlo debemos indicar una ruta relativa de donde se encuentra la imagen de la textura respecto donde se encuentre el .egg, en nuestro caso hemos copiado la textura a la carpeta maps dentro de models, por lo que sustituiremos la ruta por “./maps/textura.png”

Para ver si todo está correcto, abrimos una consola y en la carpeta donde se encuentra el .egg ejecutamos el comando pview modelo.egg sustituyendo modelo.egg por el tengamos. Debería de abrirse una ventana con nuestro modelo y su textura. Si queremos verlo con iluminación pulsamos L para añadir unas luces a la escena.


Ahora sí podremos usar el modelo en nuestro juego con su textura perfectamente definida.

martes, 8 de junio de 2010

PANDA3D: Primer contacto

En estos primeros tutoriales de panda, vamos a explicar lo mas basico, para representar  modelos, como animarlos y como mover la camara. En este ejemplo hay que tener en cuenta que los ejes, por defecto en panda estan cambiados, donde la Y es profundidad y Z, es vertical.

En el codigo intentamos explicar los pasos a seguir de este ejemplo basico.


 from math import pi, sin, cos  
 from direct.showbase.ShowBase import ShowBase  
 from direct.task import Task  
 from direct.actor.Actor import Actor  
 from direct.interval.IntervalGlobal import Sequence  
 from panda3d.core import Point3  
   
 class MyApp(ShowBase):  
   def __init__(self):  
     ShowBase.__init__(self)  
     # Cargamos los modelos del fondo  
     self.environ = self.loader.loadModel("models/environment")  
     # Pinta el modelo en la pantalla  
     self.environ.reparentTo(self.render)  
     # Aplicamos una escala y posicion  
     self.environ.setScale(0.25, 0.25, 0.25)  
     self.environ.setPos(-8, 42, 0)  
     # Aplicamos un tarea repetitiva, pasandole como parametro el nombre el metodo y un ID  
     self.taskMgr.add(self.spinCameraTask, "SpinCameraTask")  
     # Cargamos el modelo del panda creando un Actor, con el nombre del EGG para cargar y  
     # un atributo walk para realizar la animacion de andar  
     self.pandaActor = Actor("models/panda-model",{"walk": "models/panda-walk4"})  
     #Le damos una escala al panda y lo pintamos en la pantalla  
     self.pandaActor.setScale(0.005, 0.005, 0.005)  
     self.pandaActor.reparentTo(self.render)  
     # Llamamos a un metodo repetitivo pasandole el ID de los atributos de la animacion  
     self.pandaActor.loop("walk")  
     # Creamos los intervalos donde se ubicara el panda, hasta donde llegara, y que realizara.  
     # un giro de 180 grados, en 13 segundos y 3 segundos el giro.  
     pandaPosInterval1 = self.pandaActor.posInterval(13,Point3(0, -10, 0),startPos=Point3(0, 10, 0))  
     pandaPosInterval2 = self.pandaActor.posInterval(13,Point3(0, 10, 0),startPos=Point3(0, -10, 0))  
     pandaHprInterval1 = self.pandaActor.hprInterval(3,Point3(180, 0, 0),startHpr=Point3(0, 0, 0))  
     pandaHprInterval2 = self.pandaActor.hprInterval(3,Point3(0, 0, 0),startHpr=Point3(180, 0, 0))  
     # Aqui creamos la sequencia en la que utilizara uno u otro  
     # Primero empieza en y=-10 y acaba en y=10 en 13 segundos, da un giro de 180 grados  
     # en 3 segundos y despues empieza en 10 y acaba en -10.  
     self.pandaPace = Sequence(pandaPosInterval1,pandaHprInterval1,pandaPosInterval2,pandaHprInterval2,name="pandaPace")  
     # Llamada al metodo repetitivo de la sequencia de intervalos  
     self.pandaPace.loop()  
     
   # Define el procedimiento de la camara, rotanto sobre el centro de la escena  
   def spinCameraTask(self, task):  
     angleDegrees = task.time * 6.0  
     angleRadians = angleDegrees * (pi / 180.0)  
     self.camera.setPos(20 * sin(angleRadians), -20.0 * cos(angleRadians), 3)  
     self.camera.setHpr(angleDegrees, 0, 0)  
     return Task.cont  
   
 # El Main de la aplicacion.  
 app = MyApp()  
 app.run()  

Este es el resultado:



En los proximos tutoriales explicaremos, como implementar este ejemplo en la Web.

miércoles, 2 de junio de 2010

PANDA3D: Creando el entorno de desarrollo

Bueno, comenzaremos esta nueva etapa configurando nuestro entorno de desarrollo para Panda3D. Dado que hemos decidido desarrollar en Python vamos a utilizar Eclipse con el plugin PyDev, por lo que aunque el tutorial lo explico para Windows, se podrá seguir fácilmente en otros sistemas como Linux o Mac.

Para empezar necesitamos descargarnos nuestras herramientas:
  1. Eclipse IDE for Java Developers (es el más básico ya que solo queremos instalarle el plugin de PyDev)
  2. Panda3D (en el momento en que escribo estas líneas se encuentra por la versión 1.7.0)

Comenzamos instalando Panda3D que instalará en nuestro sistema el SDK para trabajar con el framework, una versión integrada de Python 2.6 configurada y lista para trabajar con Panda3D y algunos ejemplos de lo que se puede hacer con el framework. En Windows es tan simple como ejecutar, siguiente, siguiente... al final de la instalación os realizará una pregunta, yo recomiendo pulsar en SI, pero si vuestra máquina de trabajo tiene recursos limitado no lo hagáis. En otros sistemas operativos no creo que supongan mucha dificultad ya que está preparado para que sea fácil de instalar para empezar a desarrollar rápidamente.
NOTA: Puede que os indique durante la instalación de que existe otra copia de Python instalado en vuestro sistema y que Panda3D trae la suya propia preguntándoos si queréis que se use por defecto el Python de Panda3D o el que tengáis instalado en el sistema. La decisión es vuestra, solo que si seleccionáis no usar la versión de Panda3D por defecto tendréis que configurar para que reconozca las librerías de Panda3D.
A continuación descomprimimos Eclipse donde queramos y lo ejecutamos para instalarle el plugin, PyDev. Seleccionamos la carpeta donde se encontrará nuestro Workspace (en mi caso me he creado una distinta a la que indica por defecto y lo he cambiado). Para instalar el plugin nos dirigimos al menú Help y seleccionamos la opción Install new software... Aparecerá una nueva ventana donde pulsamos el botón Add... y rellenamos con un nombre el nuevo repositorio, por ejemplo "PyDev", y en Location indicamos la dirección http://pydev.org/updates. Pulsamos Ok y aparecerán los plugin de PyDev, seleccionamos el checkbox junto a PyDev (si queremos integración con el plugin Mylyn seleccionamos el otro también, en mi caso no lo usaré) y pulsamos en Next, aceptamos los términos de licencia y al final Finish. Durante la instalación nos indicará que debemos aceptar los certificados de autenticidad de Eclipse, pulsamos en Ok y en la ventana pulsamos en Select All y luego en Ok de nuevo. Tras terminar de instalar nos pedirá reiniciar Eclipse, yo recomiendo hacerlo.

Con esto tendremos Panda3D y el entorno de desarrollo instalado, solo nos falta indicarle al plugin PyDev las versiones de Python instaladas en nuestro sistema (si no tenéis ninguna otra será la de Panda3D) para utilizar la que trae el framework. Para ello nos dirigimos al menú Window y seleccionamos Preferences. Buscamos en la lista de secciones PyDev >> Interpreter - Python y en las opciones pulsamos sobre el botón Auto Config, esto escaneará el sistema buscando distintas versiones de Python instaladas. Aparecerán las carpetas que importará (deben de ser la carpeta python de Panda3D y todas sus subcarpetas) que tras pulsar en Ok quedará configurado.
NOTA: si por algún motivo da error al usar Auto Config o encuentra otras versiones de Python que tengáis instaladas en el sistema y no la de Panda3D, debéis pulsar sobre New.. y en la ventana que aparece indicáis un nombre para el intérprete de Python de Panda3D y la ruta donde se encuentre el archivo python.exe (en la carpeta python dentro de donde se instaló Panda3D). Tras pulsar en Ok aparecerá una lista de carpetas que importará (deben de ser la carpeta python de Panda3D y todas sus subcarpetas), pulsamos Ok y quedará configurado.
Para poder utilizar las librerías de Panda3D en los proyectos de Eclipse debemos añadir la carpeta de Panda3D a las carpetas del intérprete de Python (esto debemos hacerlo utilicemos el intérprete que trae Panda3D como uno que tengamos instalado), para ello vamos a la pestaña Libraries de la misma ventana y pulsamos sobre New folder y buscamos la carpeta donde hemos instalado Panda3D. Escaneará esta en busca de las librerías del framework (encontrará de nuevo las librerías que acaba de añadir, pero no lo volverá a hacer ni se solaparán). Cuando termine, pulsamos Ok en la ventana de preferencias y terminará de configurar los intérpretes. De esta forma tendremos Panda3D instalado y nuestro IDE instalado y configurado para usar la versión de Python que incluye el framework lista para trabajar.
EDITADO: Para poder añadir un autocompletado a las librerías de Panda3D, es necesario que añadáis también en el paso anterior, la carpeta bin dentro de donde esté instalado Panda3D. Pulseis en la pestaña Forced builtins y pulseis en New..., escribís la palabra direct, y repetís el proceso 2 veces más pero con las palabras pandac, panda3d y Pmw (con la P en mayúsculas). Con esto tendréis un autocompletado más o menos decente para las librerías de Panda3D.
Para los primerizos en Python (como yo :D) aquí os dejo un magnífico tutorial en PDF creado por Raúl González Duque para iniciarse en este lenguaje.



P.D Intentaré actualizar este post con la instalación en Linux y/o Mac por si aparece alguna dificultad extra que no ocurra en Windows.

lunes, 31 de mayo de 2010

Reconsiderando el camino

Como dijimos en la página de presentación de FKT, somos un pequeño grupo de personas (2) que queremos aprender a desarrollar videojuegos de forma autodidacta y sin ánimo de lucro, con la intención también de transmitir a través del blog nuestros pocos conocimientos que vamos adquiriendo, sin embargo, hemos tenido que pararnos a replantearnos la dirección que estábamos tomando ya que solo hemos encontrado problemas tras problemas en nuestro día a día en el apredizaje y nos hemos divertido bastante poco en el proceso, ya que, aunque estamos aprendiendo, también queremos ver que nuestros esfuerzos se transforman en algo tangible y nos divirtamos con lo que hacemos ya que esto lo hacemos principalmente por y para nosotros, y si no nos divertimos en ello... mal vamos.

Por eso mismo, hemos pensado que quizás para nuestros pocos conocimientos y siendo primerizos hemos intentado matar moscas a cañonazos y hemos tomado un camino un tanto complicado, lo siento por aquellos que nos seguíais por los tutoriales de Ogre3D pero vamos a dejar este framework apartado durante un tiempo indefinido y hemos decidido estudiar uno que a priori parece más fácil de aprender, y además la documentación oficial en la web parece un poco más fácil de comprender, y es lo que buscamos ahora mismo, aprender y ver que lo que aprendemos nos da resultados. En un futuro, cuando nuestros conocimientos en estos campos sean más amplios y se huna la experiencia, valoraremos si volver a rompernos la cabeza con Ogre3D o no (según los resultados que obtengamos con este nuevo framework).

Para los que nos sigáis simplemente por el gusto de aprender al igual que nosotros, espero que también disfruten con los tutoriales que iremos colgando de este nuevo camino que tomaremos. Sin más dilación os comunico que a partir de este momento seguiremos nuestras andaduras utilizando Panda3D. En su web podéis encontrar toda la información sobre este framework.

Nos apena la decisión tomada, pero como he dicho al principio, era matar moscas a cañonazos y estamos ahora mismo en proceso de aprendizaje autodidacta y aunque demos por hecho que nos encontraremos problemas, no queremos que estos sean mayor número que los éxitos.

Bueno, deciros que el framework es de código libre como Ogre3D, también se puede integrar con PhysX, se puede desarrollar tanto en c++ como en python (con soporte oficial del equipo de desarrollo del framework y no con un port como en Ogre3D) y la documentación en su web parece bastante más completa y actualizada que la que hay actualmente de Ogre3D en su respectiva web.

Espero que al menos, el nuevo framework elegido os anime a continuar con nosotros.


PD: Se me olvidaba comentar que una de las características más atractivas de Panda3D es la capacidad de incrustar en código html los juegos que se hacen y poder jugarlos desde un navegador web.

viernes, 28 de mayo de 2010

Tutorial 3 NxOgre : Kinematics

En primer lugar vamos a explicar que son y para que sirven los Kinematics, son objetos donde no le afectan el estado de fisica de otros objetos, imaginate un ascensor en un videojuegos, puedes dispararle tirarle cosas, pero en verdad no se mueve, podriamos hacer el mismo ascensor, con Volumen, pero tendriamos que controlar, si un objeto ha entrado o ha salido. Poriamos crear un body, pero a este tipo de objeto si le afecta la fisica de su entorno.

Pongo traducido un trozo del texto bastante interesante de la Wiki NxOgre:

Nota: Como siempre en NxOgre, hay que distinguir entre un cuerpo y un actor. Un actor es sólo la representación física de un objeto físico y no es visible, mientras que un cuerpo es un actor más una visualización (por ejemplo, a través de Entitys Ogre). Lo mismo se aplica para un KinematicActor y KinematicBody una.

Este se aplica a casi todo en NxOgre, un actor es la representación fisica de un objeto, el body es el objto visual en si, unido con un SceneNode de Ogre.

Para crear objetos Kinematics, se realiza así:

mKB = mRenderSystem->createKinematicBody(new NxOgre::Box(20, 2, 20), NxOgre::Vec3(0, 12, 0), "CuboF.mesh");

Le pasamos un Shape, una posición y la malla del objeto.

Voy a pasar el codigo del ejemplo construido, para que veais lo que ocurrre. SRC BloodyMessTutorial5

En este ejemplo me he encontrado dos problemas, uno que sacando la SceneNode para crear otro Kinematics, no he podido rotar dicho objeto, he tenido realizar dicha rotación con mKB->setGlobalOrientation(Quaternion), no consiguiendo del todo la rotación y tampoco uqe ningun objeto colisione, con dicho objeto una vez rotado.

Y el segundo problema y menos comprensible, si cojemos la camara del objeto la movemos y la ponemos en la parte superior del ascensor y miramos hacia abajo como si estuvieramos colgados del techo, pulsamos la tecla espacio para lanzar cubos, alguno cubos colisionan contra el ascensor y otros se escapan, es un efecto bastante curioso y no sabemos si es por cula de la poca comprensión de esta fantastica libreria o tiene errores.

Si alguien nos pudera echar una mano estariamos encantandos.

Hasta la proxima.....

miércoles, 26 de mayo de 2010

Tutorial 2 NxOgre: Volumes y Triggers

Como en anteriores tutoriales, vamos a exponer una aplicacion para descargar, que es una ligera modificación de tutorial 4 de la wiki de nxOgre. SRC NxOgre_tutorial2

Lo pimero que vamos hacer es explicar que es un volumen:

Es un tipo de objeto con sus propiedades de posición, orientación entre otras, que a la vista es invisible, pero cuando algun objeto lo atraviesa, se pueden recojer algunos eventos, para realizar alguna operación. En el ejemplo original de la wiki de nxOgre, se ve como aplicando un impulso a un cubo se ve como hace botes encima de un panel. En nuestro ejemplo hemos modificado dicho codigo, para ver el funcionamiento de dicho volumen y hemos puesto dos uno encima del otro y cada vez que toca arriba creará un cubo nuevo, así hasta 20 cubos.

El trigger no es mas que una clase que hereda de CallBack, que es la encargada de recojer los eventos. No vamos a explicar aqui todo el codigo, por que eso ya lo hicimos en anteriores post, aqui solo vamos a explicar lo que mas nos interesa.

mVolume = mScene->createVolume(new NxOgre::Box(NxOgre::Vec3(100,1,200)), NxOgre::Matrix44(NxOgre::Vec3(0, 0, 0)), this, NxOgre::Enums::VolumeCollisionType_All);

Este es el comando encargado de crear este volumen, con su Shape (como explicamos anteriormente es la envoltura), su posición, el objeto que hereda de CallBack y la ultima partes le estamos diciendo que tipo de eventos queremos recojer, en este caso son todos. Este es el metodo encargado de recojer el evento, en este caso lo tenemos en la misma clase.

void NxOgre_tutorial2::onVolumeEvent(NxOgre::Volume* volume, NxOgre::Shape* volumeShape, NxOgre::RigidBody* rigidBody, NxOgre::Shape* rigidBodyShape, unsigned int collisionEvent)
{
if(collisionEvent == NxOgre::Enums::VolumeCollisionType_OnEnter)
{
OGRE3DBody* body = static_cast(rigidBody);


float y = (9.81 * body->getMass()) // counteract gravity
+ (-body->getLinearVelocity().y * body->getMass()) // counteract vertical velocity
+ (10 - body->getGlobalPosition().y * body->getMass()); // Add some force to move it to the top


body->addForce(NxOgre::Vec3(0, y, 0), NxOgre::Enums::ForceMode_Impulse);
}
}

Como vemos aqui se pasan como parametros algunos tipo normalmente usados en este tipo de eventos. Recogemos el Volumen que ha recibido el evento, con su Shape, tambien recibimos el rigidBody, que es el objeto que ha colisionado, con su Shape y el tipo de colisión. Recordar que el OGRE3Dbody es una combinación de SceneNode(Ogre) y Actor(NxOgre).

Los tipos de colisiones mas importantes son:

  • NxOgre::Enums::VolumenCollision_Type_OnEnterOrExit - Para cuando sale o entra dentro del volumen
  • NxOgre::Enums::VolumenCollision_Type_OnEnter - Cuando ha entado el objeto dentro del volumen
  • NxOgre::Enums::VolumenCollision_Type_OnExit - Cuando ha salido del volumen
  • NxOgre::Enums::VolumenCollision_Type_OnPresence - Cuando esta completamente dentro del volumen

Este objeto nos vale para infinadad de cosas, por ejemplo podemos hacer que cuando un objeto pase por algun detrminado lugar, empieze algun sonido o musica, o por ejemplo mostrar un mensaje mmientras un objeto está dentro. Infinidad de cosas.

Seguiremos colocando tutoriales sobre esta fantastica libreria. Hasta la proxima.

martes, 25 de mayo de 2010

Tutorial NxOgre : Primer contacto


Este tutorial va acompañado e una aplicación con algunas modificaciones del segundo tutorial de la Wiki de NxOgre, interacción con estos cubos y su física y adaptación del los proyectos de la Wiki NxOgre con el BaseApplicaction que genera el OgreWizard del Vc9. En este tutorial abarcaremos el funcionamiento basico de NxOgre, para darle física a nuestros proyectos y así conseguir unos resultados mas llamativos.

Mientras explicamos como funciona brevemente las clases basicas de NxOgre, es coveniente bajar el proyecto del SVN para tener una mayor comprensión de lo que aqui exponemos. El funcionamineto de la aplicación es el siguiente, pulsar los botones:

  • V: Matener pulsado para avanzar en la animación de los cubos
  • P: Para generar mas cubos
  • B: Para que la función del boton Pse pueda borrar y crear dos cubos nuevos o generar cubos, si borrar los anteriores

En este ejmplo tan básico, lo que vemos en como crear un mundo, configurarlo y soltar varios cubos para que tenga un comportamiento acorde a la configuración. Para crear el mundo :

mWorld = NxOgre::World::createWorld();

Para darle configuración:

NxOgre::SceneDescription sceneDesc;
sceneDesc.mGravity = NxOgre::Vec3(0, -9.8f, 0);
sceneDesc.mName = "DemostrSacion FKT";


Una vez creado el mWorld y el SceneDescription, creamos la mScene
mScene = mWorld->createScene(sceneDesc);


//Configuramos el material de la escena
mScene->getMaterial(0)->setStaticFriction(0.5);
mScene->getMaterial(0)->setDynamicFriction(0.5);
mScene->getMaterial(0)->setRestitution(0.1);

Segun wikipedia la frincción es:

Se define como fuerza de rozamiento o fuerza de fricción entre dos superficies en contacto a la fuerza que se opone al movimiento de una superficie sobre la otra (fuerza de fricción dinámica) o a la fuerza que se opone al inicio del movimiento (fuerza de fricción estática).

Según entiendo despues de leer esto, que la StaticFrinction es el rozamiento que tendrá al principio del choque entre dos objetos y la DynamicFriction es el rozamiento durente todo el movimiento del choque.

Restitución:

En una colisión frontal alineada de dos esferas sólidas (como las que experimentan las bolas de billar) las velocidades después del choque están relacionadas con las velocidades antes del choque.

En definitiva es la velocidad con la que se despiden los objetos despues del choque.

// Ahora creamos el systema de renderizado, para entenderlo de alguna manera es la clase que crearemos los objetos de Ogre y todo lo demas relazionado con el.
mRenderSystem = new OGRE3DRenderSystem(mScene);

En los siguientes codigos vemos como crearemos los cubos, pasandole el BoundingBox que envolvera al objetos, la posición y el fichero .mesh. Si queremos obtener un SceneNode de un OGRE3DBody, simplemente haremos esto: mCube->getScebeNode() -> esto que devuelve el un Nodo de Ogre.

mCube = mRenderSystem->createBody(new NxOgre::Box(1,1,1), NxOgre::Vec3(0, 40, 0), "cube.1m.mesh");
mCubeTwo = mRenderSystem->createBody(new NxOgre::Box(1, 1, 1), NxOgre::Vec3(20, 45, 0), "cube.1m.mesh");
mCubeTwo->addForce(NxOgre::Vec3(-800, -200, 0), NxOgre::Enums::ForceMode_Force);

Esta es la parte mas curiosa de esta libreria, creamos un plano con BloodyMesh, pero luego dicho plano lo representamos con Ogre, si comentamos la  parte del codigo de mPlaneNode->... , veremos que el efeco de suelo sigue estando pero sin el objeto vista plano creado.

// (BloodyMess)
mScene->createSceneGeometry(new NxOgre::PlaneGeometry(0, NxOgre::Vec3(0, 1, 0)), Matrix44_Identity);


// (Ogre)
Ogre::MovablePlane *plane = new Ogre::MovablePlane("Plane");
plane->d = 0;
plane->normal = Ogre::Vector3::UNIT_Y;
Ogre::MeshManager::getSingleton().createPlane("PlaneMesh",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
*plane, 120, 120, 1, 1, true, 1, 3, 3, Ogre::Vector3::UNIT_Z);
Ogre::Entity *planeEnt = mSceneMgr->createEntity("PlaneEntity", "PlaneMesh");
planeEnt->setMaterialName("Examples/GrassFloor");


Ogre::SceneNode* mPlaneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
mPlaneNode->attachObject(planeEnt);

Aqui terminamos explicando lo basico de esta libreria, en los proximos tutoriales explicaremos colisiones con NxOgre.

Hasta la proxima.

miércoles, 19 de mayo de 2010

NVIDIA PhysX, Instalando NxOgre


PhysX es un chip y un kit de desarrollo diseñados para llevar a cabo cálculos físicos muy complejos. Conocido anteriormente como la SDK de NovodeX, fue originalmente diseñada por AGEIA y tras la adquisición de AGEIA, es actualmente desarrollado por Nvidia e integrado en sus chip gráficos más recientes. (Fuente Wikipedia)

Para poder utilizar el SDK de PhysX en nuestros desarrollos en Ogre3D utilizaremos una librería intermedia que facilita su uso llamada NxOgre.

Primero necesitamos compilar las fuentes de NxOgre para generar las librerías que utilizaremos en nuestro proyecto, para ello necesitamos tener instalado el SDK y el System Software de nVidia. A continuación descargamos NxOgre BloodyMess que es la versión estable.

Tras instalar el SDK, el System Software y descomprimir NxOgre tenemos todo lo necesario para compilar las librerías (tengo en cuenta de que disponemos del SDK de Ogre3D también en el sistema). Accedemos a la carpeta \build\msvc donde encontraremos dos proyectos preparados, para Visual Studio 2005 y 2008.

Debemos crear una variable de sistema llamada PHYSX_DIR que apuntará a la carpeta donde se instaló el SDK de PhysX.

Para compilar el proyecto debemos configurar las librerías que utilizará visual studio para compilar el proyecto. Accedemos al menú Tools y a la opcion Options...

En el apartado Projects and Solutions, en la sección VC++ Directories debemos indicar las librerías de Ogre3D necesarias para compilar el proyecto. En Include files debemos indicar la carpeta Include de Ogre3D, la carpeta Include de Samples\Commons\Include también de ogre y la carpeta boost dentro de boost_1_42 también en Ogre3D. En Executable files indicamos la carpeta bin de Ogre3D y en Library files la carpeta lib de Ogre3D y la que hay dentro de boost_1_42 también en Ogre3D.

Modificaremos las operaciones post-compilado de la librería para que no intente copiar las librerías generadas a los ejemplos Cake y Flour de NxOgre ya que si no los tenemos descargados nos dará un error de compilado que aunque nos generará las librerías correctamente, puede llevar a confusión. Para ello accedemos a las propiedades del proyecto de NxOgre y en la sección Configuration Propeties > Build Events > Post-build Event pulsamos en el botón con tres puntos en el campo Command Line y eliminamos las dos últimas lineas:
  • copy "$(SolutionDir)..\..\sdk\NxOgre_Debug.dll" "$(SolutionDir)..\..\..\BloodyCake\application\"
  • copy "$(SolutionDir)..\..\sdk\NxOgre_Debug.dll" "$(SolutionDir)..\..\..\BloodyFlour\application\"
Ahora simplemente vamos al menú Build y seleccionamos Build Solution. Según la opción de compilado obtendremos en la carpeta sdk del directorio de NxOgre una librería NxOgre.dll o NxOgre_Debug.dll, las cuales usaremos según la opción de compilado en nuestros proyectos. (Al final indico algunos posibles problemas que pueden surgir al compilar la librería y cómo solucionarlo)

Para utilizar las librerías de NxOgre con nuestro proyecto de Ogre3D debemos incluirlas de la misma forma que para compilar NxOgre. En VC++ Directories incluimos en Include files la carpeta sdk de NxOgre y en Library files también incluímos la carpeta sdk. Para utilizar las dll accedemos a las propiedades de nuestro proyecto Ogre3D y en la sección Input de Configuration Properties > Linker hacemos click en el botón con los tres puntos del campo Additional Dependences y añadimos en el campo de texto superior las siguientes lineas:
  • NxOgre.lib
  • NxOgreOGRE3D.lib
  • Si compilamos en modo Release
  • NxOgre_Debug.lib
  • NxOgreOGRE3D_Debug.lib
  • Si compilamos en modo Debug
Para terminar y poder ejecutar nuestro proyecto compilado de Ogre3D, debemos copiar las librerías NxOgre.dll o NxOgre_Debug.dll (según compilemos el proyecto) en la carpeta donde se genere nuestro ejecutable. En nuestro caso en la carpeta debug y release dentro de la carpeta bin en Ogre3D.

Para poder utilizar todos los ejmeplos que expondremos aqui hará falta el BloodyCake usado en la wiki de NxOgre el enlaze es este: MeshYUtilidades

Posibles problemas:

No deberían de producirse estos problemas si está todo bien configurado, pero por si acaso, aquí tenéis cómo solucionarlos.
  • Si al compilar no encuentra el archivo Ogre.h debemos ir a la configuración de las librerías incluidas en VC++ Directories y en Include files debemos indicar las carpetas OGRE y OIS dentro de Include en vez de solo la carpeta principal.
  • Si al compilar no encuentra el archivo OgreMain_d.lib actuaremos de la misma forma que en el punto anterior salvo que incluiremos las carpetas debug y release de la carpeta lib en la seccion Library files en vez de la carpeta principal solo.
  • Si al compilar no encuentra el archivo tss.hpp debemos copiar la carpeta boost de boos_1_42 a la carpeta Include de Ogre3D e incluirla en Include files de VC++ Directories en Visual Studio.

Espero que os sea de utilidad el tutorial Si os resulta algo difícil de seguir indicadlo en los comentarios o al mail freakteam.mail@gmail.com y le echaremos un vistazo para redactarlo de nuevo.

sábado, 15 de mayo de 2010

Primer proyecto FKT ( Pong ATARI )


Una vez leido los tutoriales anteriores, vamos a realizar nuestro primer proyecto del equipo FKT, reuniendo conocimientos.

El codigo fuente del proyecto será publico para cualquier persona que quiera participar.

http://freakteam.svn.sourceforge.net/viewvc/freakteam/trunk/PongTenis/

viernes, 14 de mayo de 2010

MOC, Minimal Ogre Collision 1.0

Vamos a intentar explicar, esta librería o utilidad, para realizar colisiones un poco mas complejas en Ogre. No veremos en su totalidad su funcionamiento en este tutorial, pero si lo mas fundamental, para realizar colisiones un poco mas complejas. Lo primero es poner en conocimiento que las imágenes y mayoría de información esta sacada de la Wiki de MOC.

Para empezar vamos a entender la diferencia de la Colisión simple explicada en el tutorial anterior con esta, y del por que de su uso. En la colisión simple por AABB, este método consistía en envolver con una caja de coordenadas la entidad y sobre dicha caja de coordenadas, preguntar sobre colisiones, pero que ocurre si la entidad no tiene la misma forma que la caja de coordenadas, la colisión no sería exacta a la entidad si no sería sobre la caja de coordenadas que la envuelve. Con esta imagen se entederá mejor lo que quiero explicar:



MOC usa el metodo del rayo,  como bien se ve en la imagen de la izquierda. Dicha colision se basa en un rayo que va dede el punto de origen al punto de destino, y colisionando sobre el objeto. Este metodo del rayo está en Raycasting_to_polygon_level. Para saber si el rayo ha colisionado en el objeto y no en su eje, este metodo, tambien necesita del metodo que devuelve la informacion de la entidad, este metodo está en RetrieveVertexData, aqui hay un metodo GetInformationMesh(...) .

Mesh es la malla que esta compuesto cualquier modelo tratado en Ogre. Cuando exportamos un modelo y lo convertimos a un fichero .Mesh, entre otras cosas, lo que se hace en dicha exportación es convertir toda la formación del objeto creado en nuestro 3dstudio, en mallas, con muchos vertices, para así despues poder leerlo. Si no se a entendido lo que he querido explicar (que será lo mas evidente :P ) un dibujo para salir de dudas:



En la imagen el Mesh sería la de la izquierda el resultado de la trasformación del dibujo de la derecha. Retomando lo que queriamos explicar, el metodo GetInformationMesh, basicamente devuelve la cantidad de vertices de un objeto,  un array con la informacion de en coordenadas de los vertices....

Una vez sabido esta informacion es preguntar con el metodo Ogre::Math::intersects, pasandole como parametros el rayo y los puntos Z,Y y Z, para saber si dicho rayo a llegado al objeto. Basicamente preguntariamos por la distancia de este rayo para saber si ha colisionado o no con el objeto.
Una vez explicado como funciona el metodo del Rayo, ya entendemos de manera basica como funciona MOC, para realizar las coslisiones.

Lo primero que debemos hacer es bajar l versión de MOC que viene en la Wiki de MOC, una vez descargada la version 1.0, desmcomprimimos el RAR, y aparece un CollisionTool.H y CollisioTool.CPP, los cojemos y lo colocamos en sus respectivas carpetas de nuestro proyecto, y ya solo con esto podemos empezar a funcionar con MOC. Vamos a intenar explicar un poco sus metodos:

Los metodos mas importantes son ()->raycast(...) y GetInformationMesh, todos los demas metodos del MOC llaman a estos dos, par devolver calculos.

  • rayCastFromCamera, -> saca un rayo desde la camara y devuelve una Entidad, con la cual a colisionado, este metodo esta bien para seleccionar objetos de la pantalla, tal cual como un juego de estrategia, que con el raton eliges un objetivo. Este metodo y el showBoundingBox del nodo podemos marcar una entidad u otra.
  • CollidesWithEntity-> devuelve un booleano, para saber si ha colisionado con un objeto o no, es un metodo facil, pero no devuelve ninguna otra informacion.
  • getTSMHeightAt y calculateY, son metodos usados, con terrenos, para saber la distancia hasta el terreno y calcular la y para saber si la camara esta por encima de un monticulo o no. Lo veremos mas adelante, en otros tutoriales de terreno.

Veamso un ejemplo de colisión con MOC:

//Resultado de la colisión, donde el rayo intercepta los verttices que componen el objeto
Ogre::Vector3 results = Ogre::Vector3::ZERO; 
//El objeto que ha sido colisionado
Ogre::Entity *tmpE = NULL;  
//Distancia hasa la colisión
float distToColl = 0; 

//Este metodo devuelve un boolean, para que sepamos cuando ha colisonado
if(col->raycast(Ogre::Ray(mSceneMgr->getSceneNode("PELOTA")->getPosition(),mSceneMgr->getSceneNode("PARED")->getPosition()),results,tmpE,distToColl,Ogre::SceneManager::ENTITY_TYPE_MASK)){
FKT::TextRenderer::getSingleton().setText("texto","Colision "+tmpE->getName());

}


Todos los demas metodos del MOC, llaman a este para reealizar las operaciones.
Con este tutoral ya podemos saber cuando un objeto  ha colsionado con otro y donde.

Hasta la proxima.

miércoles, 12 de mayo de 2010

Colisiones Simples AABB

En este tutorial, vamos abarcar la colisión, a mi manera de ver la mas simple que se puede hacer con Ogre, con la AABB, Axis Aligned Bounding Box, el eje de la caja dde coordenadas, toda esta informacion te la puedes encontrar en la Wiki de Ogre, aqui vamos a explicarla un poco y sacarle uso. En el proyecto del TENIS que estamos realizando, no vamos a incluir este tipo de Colisión, ya que utilizaremos MOC, una libreria, que explicaremos en el siguiente Tutorial.

Bueno, la caja de ejes de coordenadas, se genera el cualquier entidad generada en nuestro proyecto, podemos mostrarla para verla, con la propiedad showBoundingBox(true); del nodo asociado a esta entidad. En la sguiente imagen vemos como la caja de coordenadas envuelve a toda la entidad.


Para saber recoger esta caja, el mismo nodo que contiene la entidad nos ofrece un metodo llamado _getWorldAABB(), que nos devuelve un objeto de tipo: AxisAlignedBox, con algunos metodos interesantes

  • getMaximun(), getMinimun() -> devuelve un Vector3 con los valores maximos y minimos de esta caja.
  • getCenter() -> nos devuelve un Vector3 con el centro de la caja.
  • intersection -> pide como parametro otro AABB, y devuelve el resultante, de dicha intersección o colisión.

Ogre::AxisAlignedBox aabResultado = mSceneMgr->getSceneNode("nodo1")->_getWorldAABB().intersection(mSceneMgr->getSceneNode("nodo2")->_getWorldAABB());
if(!aabResultado.isNull())
{


" Ha habido una colision ubicada en"+aabResultado->getMaximun()->getCenter();


}

Realizando calculos, respecto a un eje, podriamos saber donde ha colisionado, por ejemplo en el tenis podriamos saber si ha colisionado en la parte de arriba centro o abajo.

  • contains -> Este metodo devuelve true o false para saber si un AABB contiene a otro.

Este metodo es muy util para saber si un objeto se encuentra o se ha encontrado alguna vez dentro de otro en su totalidad. Por ejemplo podriamos saber en el Juego del tenis si la pelota a traspasado la paleta.

En definitiva con el metodo _getWorldAABB() de los nodos, podremos saber de manera simple y facil si ha habido alguna colision entre objetos, para saber mas mirar el ejemplo creado de CuboLoco v2.

martes, 11 de mayo de 2010

FKT Utilidades

/*
-----------------------------------------------------------------------------
Filename: FKT.cpp
-----------------------------------------------------------------------------


This source file is generated by the

Ogre 1.7.x Application Wizard for VC9 (Mayo 2010)
http://www.freakteamdev.tk
-----------------------------------------------------------------------------
*/

Para hacer uso mejor de las utilidades que nos vamos encontrado por la red, vamos a publicar un .H y .CPP,
para reunirlas, con añadidos de otros compañeros que por afición van dejando esos trozos de codigo que en algun momento pueden ser muy utiles. Estará en continuos cambios en funcion del proyecto que estemos abarcando. Aqui os paso el link para la descarga del FKT.h y FKT.cpp, con dos utilidades usadas, en CuboLoco v2. Download FKTUtils

  1. EntityUtil, es una clase para recojer esa información que se encuentra en los SceneNode y tenemos que ir guardando en las variables que vamos creando en nuestro codigo, por ejemplo la variable de incremento de escala, o guardar la posicion de algun momento de la aplicacion, o un boolean para darleotro tipo de estado a un nodo o entidad, este EntityUtil se enlaza con el nombre del Nodo.
  2. TextRenderer es una utilidad muy util para realizar muestras de texto por pantalla, sin tener que utilizar el log o un label.

Su uso:

Tenemos que declararlo en cualquier parte del codigo, por ejemplo en createScene()

new FKT::TextRenderer(); // Solo lo instanciamos una vez

Y ya podemos usarlo

FKT::TextRenderer::getSingleton().addTextBox("texto","",0,0,100,200,Ogre::ColourValue::Green);

Y asi podemos hacer un Update del texto

FKT::TextRenderer::getSingleton().setText("texto",Ogre::StringConverter::toString(aab.getSize()));

Este texto debes de tener instalado en los archivos OGRE_HOME/media/fonts/sample.fontdef el Font Starwars, es el tipo de letra que usa.

domingo, 9 de mayo de 2010

2º Versión del CuboLoco, ahora con colisiones

Aqui presentamos la 2º version del CuboLoco, ahora con colisiones simples, utilizando la AABB, Eje Coordenadas de la Caja Alineados.


Siguientes tutoriales explicaremos colisiones simples....

sábado, 1 de mayo de 2010

Rotate, position y Scale


Ampliando el tutorial primero de la wiki de Ogre, vamos a realizar un ejercicio de un Cubo, rotando sobre si mismo y chocandose, con las paredes de la ventana, para ir reforzando los tutoriales anteriores con este. Basicamente es un ejemplo de reocjer los enventos de los botones, hacer operaciones basicas sobre un cubo.

En la version de codigo fuente, está la carpeta del projecto en VS2008, mas una carpeta media, que deberis copiar y pegar en OGRE_HOME, que son los modelos, el archivo material y el png del logo.


En la version ejecutable del ejemplo, se ejecutará solo en modo OpenGL, para verlo en con DirectX, necesitas tener instalada la verson DirectX, la misma que desatives en puglins.cfg.

viernes, 30 de abril de 2010

Personalizando nuestras aplicaciones 2ª (Botones, Labels ....)

En este tuturial aprenderemos a crear nuestro botones y labels, y demas utilidades que nos ofrece la GUI de Ogre.

En la clase SdkTraylistener, explicada un poco por encima en el tutoriales anteriores, esta clase ademas de crear botones, labels... un largo etc, es utilizada tambien para recojer sus estados. Vamos a intentar explicar una parte del codigo que se dedica a registrar los eventos de la ventana a la libreria de Ogre.

En el metodo BaseApplication::createFrameListener() esta el siguiente codigo:

//Este codigo es para meter registros de log en el fichero Ogre.log, de la capeta bin\debug o release
Ogre::LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
//Creamos una lista de parametros del OIS
OIS::ParamList pl;

Inicializamos un mejador de ventanas, tambien llamado en la API WIN32: HWND, digamos que es un identificador de la ventana, cada ventana de window que abres en tu S.O. necesita un identificador, pues estamos registrando el que nos a dado WindowsXP.

size_t windowHnd = 0;


//Creamos un flujo de entrada para crear valores String
std::ostringstream windowHndStr;


//El objeto mWindow es la venta fisica que acaba de crear nuestro programa en el S.O. le pasamos el windowHnd para que nos devuelva el identificador de ventna creado.
Se lo damos al flujo de entrada y se crea un String con un numero que se lo introducimos al ParamList
mWindow->getCustomAttribute("WINDOW", &windowHnd);
windowHndStr << windowHnd; pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str())); //Aqui creamos el InputManager con este PAramList creado anteriormente, que es el objeto padre que recojera cualquier evento producido en la ventana, raton, teclado, minimizar, maximizar.... mInputManager = OIS::InputManager::createInputSystem( pl ); //Creamos los objetos mKeyBoard y mMouse con ese InputManager y al ser el BaseApplication una clase derivada de KeyListener y MouseListener, les añadimos mKeyBoard y mMouse esta clase para recojer sus eventos. mKeyboard = static_cast(mInputManager->createInputObject( OIS::OISKeyboard, true ));
mMouse = static_cast(mInputManager->createInputObject( OIS::OISMouse, true ));


mMouse->setEventCallback(this);
mKeyboard->setEventCallback(this);


//Aqui establecemos el tamaño de ventan para darle un ancho y alto al nuestro raton
windowResized(mWindow);


//Registramos en Ogre la ventana y el BAseApplication que deriva de WIndowEventListener
Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this);


//Aqui inicializamos en objeto SdkTrayListener con la ventana, el raton y el BaseApplication
mTrayMgr = new OgreBites::SdkTrayManager("InterfaceName", mWindow, mMouse, this);
//Aqui muestra el panel de FPS
mTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT);
//Inicializa nuestro Logo, ya modificado en el tutorial anterior
mTrayMgr->showLogo(OgreBites::TL_BOTTOMRIGHT);


//Una vez explicado esto ya entendemos como se enlaza la ventana con la librearia Ogre y OIS, para recojer los eventos del MouseListener y KeyListener y sus metodos:


virtual bool keyPressed( const OIS::KeyEvent &arg );
virtual bool keyReleased( const OIS::KeyEvent &arg );
virtual bool mouseMoved( const OIS::MouseEvent &arg );
virtual bool mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id );
virtual bool mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id );

Una vez echo esto en el metodo createFrameListener() al final vamos a crear un boton y un label :

mTrayMgr->createButton(OgreBites::TL_BOTTOM, "Boton","Esto es un boton",200);
mTrayMgr->createLabel(OgreBites::TL_TOP,"Label","FrakTeam Logo",400);

Con estos metodos creamos dos Widgets dentro de la clase mTrayMgr, los Widgets con la clase Padre de todos los elementos creado de SdkTray. Utilizamos el metodo mousePressed, para saber que ha pulsado:

bool personalizando2::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id){
if(mTrayMgr->injectMouseDown(evt,id)){
OgreBites::Label *label = static_cast(mTrayMgr->getWidget("Label"));
OgreBites::Button *boton = static_cast(mTrayMgr->getWidget("Boton"));
if(boton->getState() == OgreBites::BS_DOWN){
label->setCaption("Has pulsado el boton");
} else {


label->setCaption("No es el boton");
}
return true;
} else {
static_cast(mTrayMgr->getWidget("Label"))->setCaption("Has pulsado en vacio");
}
mCameraMan->injectMouseDown(evt,id);
return true;


}

Compilamos y veremos algo así:


Como vemos en este codigo cojemos el evento MouseEvent y el boton pulsado del raton MouseButtonID, y se los pasamos a mTrayMgr->injectMouseDown(), este metodo busca todos sus Widgets, creado por la posición y cambia el estado del pulsado por el cursor, dependiendo la posición del mismo.

Un vez pasado el metodo injectMouseDown, si hemos pulsado el boton habrá cambiado su estado, utilizamos el metodo getWidget(Nombre), y le realizamos un static_cast a OgreBites::Button, hacemos la conversión de Widgets a Button, preguntamos por su estado y vemos que es OgreBitess::BS_DOWN, y cambiamos el valor del caption del Label, realizando la misma operación de sttatic_cast.

Esto es un ejemplo, pero lo suyo es tener objetos Button y Label como privados, para no tener que realizar un static_cast cada vez que pulsemos un boton en nuestra aplicación, de todas formas solo es un ejemplo.

El metodo de mCameraMan->injectMouseDown(), como expliqué en tutoriales anteriores, este objeto es para utilizar los eventos de la camara, si no hemos pulsado ningun Widgets, entoces le pasa el valor del raton a la camara.

Aqui os paso el Codigo de ejemplo por si lo quereis ver y realizar Debug. SRC Ejemplo

Aqui os paso los binarios del programa solo para Windows. Se ejecutará en modod OpenGL, si quieres ejecutarlo en modo DirectX, necesitas terner instalado los Directx en tu equipo y descomentar el fichero plugins.cfg, la linea:

Plugin=RenderSystem_Direct3D9
# Plugin=RenderSystem_Direct3D10
# Plugin=RenderSystem_Direct3D11

Descomenta dependiendo la que tengas.

Binarios Ejemplo