Transformaciones de escena en JMonkeyEngine

0
11584

Transformaciones de escena en JMonkeyEngine

En Autentia seguimos investigando sobre JMonkeyEngine y el
mundo de los juegos en Java.

Para estos ejemplos partimos de la base de tener instalado JMonkeyEngine,
NetBeans y Blender
.

Aunque hay personal dedicado a ello no me resigno a
solventar mi frustración (la de los jefes frikis) de cacharrear con estas cosas y voy a ir compartiendo mis pruebas personales. Os recuerdo que podréis encontrar otros tutoriales quizá más avanzados en este enlace de adictosaltrabajo.com: Juegos
y 3D.

Voy a empezar con la guía e iré cogiendo ejemplos de aquí y allá para probar los conceptos básicos (o no tantos). Tenemos que empezar a posicionar elementos por la escena y transformarlos: Rotaciones, traslaciones y escalados. También trataremos de ver como ver lo que hay en la escena y editarlo, incluso crear escenas desde programas externos.

Empezamos en: http://wiki.jmonkeyengine.org/doku.php/

Voy a seguir los tutoriales y ver si están actualizados y
como me van llevando por el camino del conocimiento. En NetBeans voy a crear
una primera clase.

Ojo que a mí este código no me funciona y hay que cambiar un par de funciones:


public static void main(String[] args) {

TestSphere app = new TestSphere();

app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG);

app.start();

}

Y lo he tenido que cambiar por este

JMEjemplo1 app = new JMEjemplo1();

app.setConfigShowMod(ConfigShowMode.AlwaysShow);

app.start();

Tendremos que poner más atención a las versiones.
Investigamos en la documentación para ver cómo sacar dinámicamente la versión que estamos usando:

Vamos al Javadoc a trastear un poco http://wiki.jmonkeyengine.org/doku.php/

Al leer la versión en nuestro programa

logger.log(Level.INFO, «La versión es: » +
app.getVersion());

Nos aparece:

INFO: La versión es: jME version 2.0 dev build 2

Vamos con las trasformaciones de la escena actual. Me
gustaría ver en diagonal lo que voy haciendo dentro de mis ejes: Entonces,tengo dos opciones: Rotar/mover la cámara o rotar lo que pinto. Ya os digo que a priori parece más sensato mover la cámara pero esto es tan solo un ejemplo.

Voy a empezar a mover lo que pinto. Usaremos este código
fuente.


package adictosaltrabajo;

import java.util.logging.Logger;

import com.jme.app.SimpleGame;

import com.jme.math.Vector3f;

import java.util.logging.Level;

import com.jme.scene.shape.*;

import com.jme.math.Quaternion;

import com.jme.math.FastMath;

/**

 *

�* Roberto Canales Basado en ejemplos de

 * @author Jack Lindamood

�*/

public class EjemploRotaciones extends
SimpleGame {

private static final Logger logger =
Logger.getLogger(EjemploRotaciones.class.getName());

	private Quaternion q1 = new Quaternion();

	public static void main(String[] args){

	EjemploRotaciones app = new EjemploRotaciones();

      logger.log(Level.INFO, "La versi�n es: " + app.getVersion());

	app.setConfigShowMode(ConfigShowMode.AlwaysShow);

      app.start();

 }



	protected void simpleInitGame() {


		q1.fromAngles(0, -FastMath.QUARTER_PI, 0);

		rootNode.setLocalRotation(q1);

		// Pintar los ejes de coordenadas

		AxisRods ejes = new AxisRods("ejes", true, 5.0f);

		rootNode.attachChild(ejes);


		// Pintar una caja

		Box b = new Box("MiCaja", new Vector3f(0, 0, 0), new Vector3f(2, 2, 2));

		b.setLocalTranslation(3, 0, 3);

		rootNode.attachChild(b);

		}

	}

Como veis, hemos rotado 45 grados en el eje y (en radianes) apoyándonos en el método setLocalRotation y la clase Quaternion que nos simplifica la gestión respecto al uso de matrices.

Os pongo también el ejemplo de cómo podríamos hacer para rotar la cámara alrededor del eje:

package adictosaltrabajo;


import java.util.logging.Logger;

import com.jme.app.SimpleGame;

import com.jme.math.Vector3f;

import java.util.logging.Level;

import com.jme.scene.shape.*;

import com.jme.math.Quaternion;

import com.jme.math.FastMath;

import com.acarter.scenemonitor.*;

/**

 *

 * Roberto Canales Basado en ejemplos de

 * @author Jack Lindamood

�*/ public class EjemploRotaciones extends SimpleGame { private static final Logger logger = Logger.getLogger EjemploRotaciones.class.getName()); private Quaternion q1 = new Quaternion(); // varibles para hacer cosas una vez cada segundo private long tini = System.currentTimeMillis(); private long tfin = tini; // variables para el movimiento de la cámara private float angulo = 0; private Vector3f poscamara = new Vector3f(0, 0, 45); // contador para controlar la elevacion private int contador = 0; public static void main(String[] args){ EjemploRotaciones app = new EjemploRotaciones(); logger.log(Level.INFO, "La versión es: " + app.getVersion()); app.setConfigShowMode(ConfigShowMode.AlwaysShow); app.start(); } protected void simpleInitGame() { q1.fromAngles(0, -FastMath.QUARTER_PI , 0); rootNode.setLocalRotation(q1); // Pintar los ejes de coordenadas AxisRods ejes = new AxisRods("ejes", true, 5.0f); rootNode.attachChild(ejes); // Pintar una caja

Box b = new Box("MiCaja", new Vector3f(0, 0, 0), new Vector3f(2, 2, 2)); b.setLocalTranslation(3, 0, 3); rootNode.attachChild(b); //SceneMonitor.getMonitor().showViewer(true);

//SceneMonitor.getMonitor().registerNode(rootNode);

} // bucle de juego

protected void simpleUpdate() {

if (tpf < 1){ angulo = angulo + (tpf * 1);

if (angulo > 360) {

angulo = 0;

} } // establecemos la posici�n alrededor del eje y poscamara.set((float)(45*Math.sin(angulo)),contador,(float)(-4 *Math.cos(angulo))); cam.setLocation(poscamara); // cambiamos la posici�n de la cámara cam.lookAt(Vector3f.ZERO,new Vector3f(0,1,0)); //que mire al punto 0 en vertical // vamos a ver la posicion y orientaci�n de la cámara tfin = System.currentTimeMillis(); if(tfin - this.tini > 1000) //cada segundo { tini = tfin;// vamos a volcar cada segundo la posici�n de la cámara Vector3f camarapos = this.cam.getLocation(); logger.log(Level.INFO, "La camara est´ en : " + camarapos.toString()); Vector3f camaraor = this.cam.getDirection(); logger.log(Level.INFO, "La camara apunta a : " + camaraor.toString()); contador++; } } }

Hemos dicho que es mejor rotar la cámara porque sino,
pierdes las referencias de las coordenadas absolutas.

Si volvemos a nuestras transformaciones de los objetos de la
escena, habrá veces que querremos concatenar transformaciones o hacer cosas especiales como rotar todo desde un punto. Para ellos, simplemente tenemos que crear nodos intermedios o anidados para aplicar esos efectos. Podeis ver como se hace en este enlace y una mejor explicación:

http://wiki.jmonkeyengine.org/doku.php

Os propongo este código para entenderlo mejor:

package adictosaltrabajo;

/**

 * @author Base http://www.jmonkeyengine.com/wiki/doku.php?id=rotate_about_a_point
 
 */

import java.util.logging.Logger;

import com.jme.app.SimpleGame;

import com.jme.math.Vector3f;

import java.util.logging.Level;

import com.jme.scene.shape.*;

import com.jme.math.Quaternion;

import com.jme.scene.*;

import com.jme.bounding.*;

public class JMEjemplo1 extends SimpleGame{

	private static final Logger logger = Logger.getLogger(JMEjemplo1.class.getName());

	private Quaternion rotQuat1 = new Quaternion();

	private Quaternion rotQuat2 = new Quaternion();

	private float angle = 0;

	private Vector3f axis = new Vector3f(0, 1, 0);

	private Sphere s;

	private Sphere moon1, moon2;

	private Node pivotNode1, pivotNode2, pivotNode3;

	long tini = System.currentTimeMillis();

	long tfin = tini;

	/**

	 * Entry point for the test,

	 * @param args

	 */

	public static void main(String[] args){


		JMEjemplo1 app = new JMEjemplo1();

		app.setConfigShowMode(ConfigShowMode.AlwaysShow);

		app.start();

	}


	protected void simpleUpdate() {

	if (tpf < 1) {

		angle = angle + (tpf * 1);

		if (angle > 360) {

			angle = 0;

		}

	}

	rotQuat1.fromAngleAxis(angle, axis);

	pivotNode1.setLocalRotation(rotQuat1);

	//Moon 2 orbits twice as fast

	rotQuat2.fromAngleAxis(angle * 2, axis);

	pivotNode2.setLocalRotation(rotQuat2);

	tfin = System.currentTimeMillis();

	if(tfin - this.tini > 1000)

	tini = tfin;

	Vector3f camarapos = this.cam.getLocation();

	logger.log(Level.INFO, "La camara est� en :" + camarapos.toString());

	Vector3f camaraor = this.cam.getDirection();

	logger.log(Level.INFO,"La camara apunta a : " + camaraor.toString());

	}

}

protected void simpleInitGame() {

	display.setTitle("jME - Rotaci�n alrededor de un punto");

	// Pintar los ejes de coordenadas

	AxisRods ejes = new AxisRods("ejes", true, 100.0f);

	rootNode.attachChild(ejes);

	//Planet

	s = new Sphere("Planeta", 25, 25, 25);

	s.setModelBound(new BoundingSphere());

	s.updateModelBound();

	//Moons

	moon1 = new Sphere("Luna1", 25, 25, 10);

	moon1.setModelBound(new BoundingSphere());

	moon1.updateModelBound();

	moon1.setLocalTranslation(40, 0, 0);

	pivotNode1 = new Node("PivotNode 1");

	pivotNode1.attachChild(moon1);

	moon2 = new Sphere("Luna2", 25, 25, 7.5f);

	moon2.setModelBound(new BoundingSphere());

	moon2.updateModelBound();

	moon2.setLocalTranslation(60, 0, 0);

	pivotNode2 = new Node("PivotNode 2");

	pivotNode2.attachChild(moon2);

	pivotNode3 = new Node("PivotNode 3");

	pivotNode3.setLocalTranslation(100, 0, 0);

	pivotNode3.attachChild(s);

	pivotNode3.attachChild(pivotNode1);

	pivotNode3.attachChild(pivotNode2);

	rootNode.attachChild(pivotNode3);

	}

}

Hemos creado un nodo hijo (el 3) y hemos hecho que los demás
sean hijos a su vez. Como el primero le hemos movido (traslate), todos los demás parten de esas coordenadas.

Bueno, está entendido como se realizan las transformaciones.
Es un buen momento para añadir el código de la consola de la escena y ver qu&eacte; está pasando. SceneMonitor es una herramienta que nos permite ver la estructura de nodos de nuestro programa actual.

Vamos al link del producto/librería http://code.google.com/p/scenemonitor/wiki/SceneMonitor

No es muy grande.

Descomprimimos los ficheros en un directorio.

Las añadimos a nuestro proyecto en NetBeans (pulsando el
botón derecho en la carpeta de libarías)

En nuestro programa solo hay que añadir un par de líneas
(eso sí, tampoco se os olvide el import com.acarter.scenemonitor.*;)

Y lo curioso es no solo que vemos la estructura de la escena
sino que «la podemos modificar» y cambiar la posición de los elementos.

Bueno, vamos a probar lo mismo con la mosca importada de
blender a ver si se corresponden los nodos con los mismos nombres que les di
dentro de la herramienta (recordad que todo esto está descrito en los tutoriales anteriores sobre blender).

Pues efectivamente vemos que nos conserva los nombres de los
nodos y dentro est´n nuestros elementos. Cambio atributos de las alas y vemos como le afecta (importante porque nos da pistas de cómo pintar los objetos para
no encontrarnos luego problemas ya en nuestro programa):

Este es el aspecto de la consola. Jugad con ella cambiando
atributos,curioso.

Si queréis comprobar que es lo que pasa al importar
cualquier otro formato de fichero os invito a que reviséis este ejemplo que
viene con JMonkeyEngine. Es un programa gráfico que te permite navegar por los directorios y cargar cualquier fichero de los formatos soportados: ModelLoader.java

http://code.google.com/p/jmonkeyengine/source/browse/trunk/src/com/jmex/model/util/ModelLoader.java

Directamente en el código vemos los formatos.

Para arrancarlo solo tenéis que modificar las características
del proyecto en NetBeans y elegir la clase principal de arranque.

Elegimos un fichero 3DS.

Y vemos cómo queda. Si el fichero contiene una animación esta se activará.

No se si os habeís fijado en que hay otro programa llamado
SceneWorker que viene a hacer una mezcla de las cosas anteriores.

Vamos a la sección de descargas y nos bajamos el fichero de
SceneWorker StandAlone

Los descomprimimos en un directorio y ejecutamos el bat.

Podemos insertar en la escena cualquier elemento como
terrenos, figuras básicas, el cielo, etc.

Está francamente bien porque te dá incluso una idea más
directa de los atributos que tendrías que tocar en tus programas para hacer lo mismo.

Vamos a importar en la escena un fichero de otro programa.
Los ficheros JME son los de JmonkeyEngine. Si usasteis la clase ModelLoader
descrita más arriba comprobareis que cada vez que cargais un fichero en otro
formato, en el mismo directorio, te genera un fichero JME. Tambien este
programa guarda todos los trabajos con extensión JME (se la tienes que poner
tu).

Vamos a cargar el muñequito que anda usado en otros ejemplos
del site.

Y no lo carga en nuestra escena (moviéndose)

Bueno, lo vamos a dejar por aquí. Espero que hayáis vistos
las posibilidades de manipulado de la escena: Transformar nodos, mover la cámara,
ver la escena en memoria, importar ficheros externos, generar tus ficheros JME
(aunque es trasparente puedes recorrer el código y ver como lo hace… que
podría estar chupao para captar instantáneas) y generar escenas de un modo externo.

Cuanto más investigo más me gusta esto.

Voy a compartir con vosotros algunos enlaces de interés
sobre cosas que deberíamos investigar. Lo dejamos ya para otro momento.

Un juego de tanques con fuentes incluidos: http://sourceforge.net/projects/tankbattles/files/tankbattles/tankBattles-pre-alpha-R03.zip

Y una librer&iacutea para hacer los cr&eacuteditos y formularios de
nuestros juegos

http://www.fenggui.org/doku.php?id=doc:examples:examples

También veréis que el camino de los juegos y la edición de
escenarios van muy ligada por lo que deberíamos trabajar en esta línea
paralelamente.

Primero visitar el Web de www.blender.es
donde encontrareis cosas curiosas como plantillas con las teclas rápidas,
enlaces a cientos de texturas y demás cosas.

Aceleradores de teclas de Blender http://www.blender.es/documents/BlenderHotkeys.pdf

Desde luego hay que dar gracias a mucha gente, hay que ver
como se lo curran.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad