Archivo

Archive for 19 octubre 2008

Agua animada con Blender y Java 3D (parte 2)

19 octubre, 2008 11 comentarios

En la primera parte se explica cómo crear superficies de agua en Blender y exportarlas como archivos .obj apropiados para utilizar con Java 3D. En esta parte se explica cómo importar archivos .obj en Java 3D y utilizarlos para hacer una animación de una superficie de  agua.

Debo aclarar que todo lo que está a continuación no es más que la adaptación del ejemplo Morphing, que se encuentra incluido entre los ejemplos disponibles en la parte 1. La clase MorphingBehavior, que debe incluirse en el proyecto, también está incluida en ese ejemplo, NO es alguna clase que yo haya hecho, sólo la utilizo. El ejemplo terminado (como proyecto de NetBeans) se encuentra aquí:

Agua.zip

Toda la explicación siguiente se basa en el método crearAgua() de la clase Agua, por lo que recomiendo descargar el ejemplo, abrir el archivo Agua.java en su editor favorito y buscar el método mencionado. El código está muy bien comentado (según lo que entendí del ejemplo original).

¿List@? Muy bien. En primer lugar, el método crearAgua() retorna un objeto BranchGroup porque este tipo de objeto permite ser “compilado”. Java 3D lo compila y lo almacena en caché, con el propósito de mejorar el rendimiento. Sin embargo, esto evita que el objeto devuelto pueda ser modificado, aunque no veo por qué debería hacerse. En todo caso, con un poco de experiencia en Java es posible modificarlo de modo que el objeto devuelto sea un TransformGroup.

De manera general, éstos son los pasos que componen el método:

  1. Se declara e instancia el BranchGroup que se va a devolver.
  2. Se definen las transformaciones necesarias para que el agua se “ajuste” a nuestro universo (creado en el constructor). Estas transformaciones consisten en aplicar una escala ya sea para agrandar o reducir la superficie (según convenga); y rotar toda la superficie 90º sobre el eje x, para que la superficie sea horizontal. De lo contrario es como si el agua se viera desde arriba, y lo que es peor, no sería lógico en el sistema de coordenadas del universo, al tener una superficie de agua vertical.
  3. Se crea una esfera para limitar la aplicación de la iluminación y el fondo de la escena. También se usa para indicar cuándo debe activarse el objeto Behavior de la animación.
  4. Se carga una imagen y se utiliza como fondo para simular el cielo. Esto es opcional.
  5. Se definen las luces ambiental y direccional. La primera es para que el material de la superficie de agua refleje su color y la segunda para acentuar las olas con sombras y reflejos. Yo diría que esto es necesario, de lo contrario el agua se vería como un simple plano.
  6. Se declaran e instancian distintos vectores de objetos de Java 3D para contener y manipular las superficies distintas en distintas “etapas” desde que se cargan, hasta ser unidas en una animación.
  7. Se cargan las superficies y se manipulan en los vectores definidos en el paso anterior.
  8. Se define un objeto Appearance para el agua. Aquí se establecen el color y la brillantez de la misma.
  9. La apariencia anterior, junto con uno de los vectores, se utiliza para crear un objeto Morph que permite transformar las distintas geometrías contenidas en el vector, una en otra.
  10. Se crea el objeto Alpha que controlará la velocidad de la animación.
  11. El objeto Morph y el objeto Alpha se utilizan para instanciar un objeto MorphingBehavior (la única clase que debe copiarse al proyecto). Esta clase une la transformación de las geometrías con el tiempo para que sea realizada. Y se agrega directamente al BranchGroup que se retornará.
  12. Cuando la superficie de agua se ve “de lado”, muchos polígonos desaparecen. Lo único que hay además del agua es el fondo, por lo que sólo se ven un montón de olas que más parecen gaviotas volando. Recomiendo comentar la línea 182 para comprender a qué me refiero. Lo que hice para solucionar esto fue crear un objeto Box que actúa como un fondo extra, para evitar que se vea el fondo de cielo. Al final esta caja resulta siendo una parte considerable del agua. Por eso es que se crea un nuevo objeto Appearance para darle a la caja un color azul. Y obviamente también se crea la caja. También se le aplican transformaciones para ubicarla donde debe quedar y completar el efecto deseado.
  13. Finalmente se compila y se retorna la rama.

Con esto es suficiente para poder utilizar agua en cualquier proyecto con Java 3D que se desee, basta con copiar el método. Pero esa no es la gracia tampoco. Además del método crearAgua() lo único que hay en la clase Agua es su constructor y el método main(). En el constructor se configura el layout de la ventana y se crea un Canvas3D para dibujar allí el universo, que también se instancia allí. Hay unas líneas que configuran el punto de vista del universo para que el agua se vea ligeramente desde arriba, y por último se agrega la rama del agua al universo llamando al método crearAgua(). En el método main() sólo se agrega el Applet devuelto por el constructor a un MainFrame para verlo en una ventana.

Ésta es una muestra del resultado final (la animación real es mucho más fluida y no se ve tan rítmica, pero sólo es para darse una idea):

Agua

Y con esto finalmente termina esta explicación para crear agua animada en Java 3D con la ayuda de Blender. Espero que sea de utilidad.

Anuncios
Categorías:Programación Etiquetas: , , , ,

Agua animada con Blender y Java 3D (parte 1)

9 octubre, 2008 5 comentarios

Bueno, en uno de mis proyectos de la U me tocó representar agua en Java 3D. Buscando entre unos ejemplos (muy buenos) disponibles aquí encontré uno sobre transformar una figura tridimensional en otra. Empecé a estudiar el ejemplo y vi que es posible cargar archivos de tipo .obj (archivos de texto con coordenadas tridimensionales que representan objetos) desde Java 3D. Entonces pensé en crear distintas mallas de agua ligeramente diferentes y transformar una en otra para simular las ondulaciones del agua.

Lo difícil era entonces crear esas mallas. Y aquí entra Blender. Es posible exportar figuras como archivos .obj. Y mejor aún, existe una manera muy simple de crear estas mallas en minutos. Eso sí, las simulaciones de superficies de agua hechas con Blender que se encuentran en internet suelen valerse de texturas, que no se exportan adecuadamente porque la sintaxis de los archivos .obj de Blender no es soportada por completo por Java 3D, entonces lo mejor es usar una malla (grid) "moldeada" como una superficie de agua. Pero en serio, es muy fácil.

Lo primero es obvio, eliminar el cubo que viene por defecto en el archivo nuevo de Blender. Sugiero tener cuidado de no mover el cursor para que todo lo que se cree aparezca en el centro. Y luego se agrega un objeto "Grid" (la malla que se va a moldear).

También se deben eliminar la cámara y el foco que vienen en el archivo nuevo. De verdad, no son necesarios en Java 3D, pues tiene su propia forma de lidiar con la vista y la iluminación.

Para la malla se va al menú Add > Mesh > Grid. Luego Blender solicita las dimensiones, sugiero que ambas sean menores a 100, alrededor de 50 funciona bien. Éste es el resultado, con la vista "Top" (por defecto).

Luego se cambia a cualquier vista que permita ver a la malla horizontalmente. Yo uso la frontal.

La razón es que es mucho más fácil lograr un desplazamiento únicamente vertical para las siguientes transformaciones que hay que hacer. También recomiendo aumentar el zoom para que la malla ocupe casi todo el ancho de la ventana. Esto permite ver las líneas de medición que proporciona Blender y permite calcular mejor el desplazamiento necesario.

 

Lo siguiente es cambiar el modo de la vista de "Object Mode" a "Edit Mode". Eso se puede hacer con la tecla Tab. Posteriormente se deselecciona todo, con la tecla A. Habiendo hecho esto se va al menú Select > Random… Recomiendo usar el 50% que está por defecto.

Esto selecciona la mitad de los puntos que componen la malla al azar. Lo que resta es tomar la flecha de la selección que apunta hacia arriba (flecha z) y arrastrarla hacia arriba o abajo. Ojo, no mucho. Luego se deselecciona todo de nuevo con A y se vuelven a seleccionar la mitad de los puntos al azar. Luego se toma de nuevo la flecha de z, pero se mueve en la dirección opuesta a la anterior.

El resultado es una bonita superficie aleatoria que, si no somos muy exigentes, pasa por agua.

 

 

 

 

La renderizada no es necesaria, lo que sigue es exportar la malla.

Para exportar se va al menú File > Export > Wavefront (.obj)… Luego se selecciona la ubicación y nombre del archivo (es un poco confuso) y hecho esto, recomiendo deseleccionar todas las opciones que aparecen. De nuevo, esto se debe a la sintaxis del archivo que se genera. Sería necesario hacerle cambios para que funcione en Java 3D si se exportara cualquier otra cosa.

 

Todo el proceso se repite dos veces más, de modo que el resultado final son tres archivos .obj. Para facilitar su uso con Java todos deben tener el mismo nombre, seguido de un número. Los números deben ser correlativos (lo mejor es usar 0, 1 y 2, por ejemplo Agua0.obj, Agua1.obj y Agua2.obj).

En la siguiente parte explicaré a grandes rasgos la utilización de estos archivos y cómo transformarlos para hacer la animación del agua.

Categorías:Programación