Java 3D
Autores: Carlos de Tapia Miguel del Corral Aníbal Chehayeb Morán
Tabla de Contenidos
13.1 INTRODUCCIÓN ........................................................................................................ 5 13.1.1 ¿Qué es Java 3D? ............................................................................................. 5 13.1.2 Objetivos.............................................................................................................. 5 13.1.3 Cómo ver un objeto en 3D siguiendo un grafo ......................................... 6 13.1.4 Paradigma de programación.......................................................................... 7 13.1.4.1 Modelo de programación del grafo de escena .............................. 7 13.1.4.2 Aplicaciones y applets..................................................................... 7 13.1.5 Explicación de la estructura de trabajo....................................................... 8 13.2 CONCEPTOS GENERALES.................................................................................. 10 13.2.1 Objetos del grafo de escena......................................................................... 11 13.2.1.1 Objetos de la superestructura del grafo de escena .................... 12 13.2.1.2 Objetos de agrupación de nodos.................................................. 13 13.2.1.3 Objetos nodos hoja........................................................................ 14 13.2.2 Otros objetos implicados.............................................................................. 16 13.2.3 Construcción de un árbol ............................................................................. 17 13.2.3.1 Grafos de escena ilegales ............................................................. 18 13.2.4 Sistema de coordenadas............................................................................... 19 13.2.4.1 Coordenadas de alta resolución ................................................... 20 13.2.5 Modos de renderización ................................................................................ 21 13.2.6 Paquetes Java 3D............................................................................................ 23 13.3 MODELO DE CONTENIDOS ................................................................................. 24 13.3.1 Sistemas de coordenadas y paquete javax.vecmath ............................ 24 13.3.2 Formas geométricas....................................................................................... 26 13.3.2.1 Formas geométricas predefinidas ................................................ 27 13.3.2.2 Construcción de elementos geométricos .................................... 28 13.3.2.3 Texto 2D y 3D.................................................................................. 33 13.3.2.4 Ayudas a la construcción de figuras geométricas...................... 34 13.3.2.5 Cargadores de escenas 3D ........................................................... 35 13.3.3 Modificación de la apariencia ...................................................................... 37 13.3.3.1 Concepto de límite ......................................................................... 37 13.3.3.2 Configuración del fondo ................................................................ 38 13.3.3.3 Apariencia ....................................................................................... 39 13.3.3.3.1 Atributos generales.......................................................................... 40 13.3.3.4 Luces............................................................................................... 42 13.3.3.4.1 Modelos implicados ......................................................................... 42 13.3.3.4.2 Fuentes de luz ................................................................................... 45 13.3.3.4.3 Clase Material .................................................................................... 46 13.3.3.4.4 Influencia de las fuentes de luz .................................................... 47 13.3.3.5 Texturas .......................................................................................... 47
2
13.3.3.5.1 Clases esenciales de texturado.................................................... 49 13.3.4 Movimiento en Java 3D.................................................................................. 52 13.3.4.1 Conceptos básicos ........................................................................ 52 13.3.4.1.1 Traslaciones y rotaciones en Java 3D ........................................ 52 13.3.4.1.2 Concepto de capacidad .................................................................. 53 13.3.4.1.3 Comportamientos ............................................................................. 53 13.3.4.2 Interacción con el usuario ............................................................. 56 13.3.4.2.1 Interacción a través del teclado.................................................... 57 13.3.4.2.2 Gestión del ratón .............................................................................. 58 13.3.4.2.3 Discriminación de objetos ............................................................. 58 13.3.4.3 Animación en Java 3D ................................................................... 60 13.4 MODELO DE VISUALIZACIÓN............................................................................. 68 13.4.1 Justificación ..................................................................................................... 68 13.4.2 Influencia del entorno físico en la vista .................................................... 69 13.4.2.1 Sistema montado en la cabeza ..................................................... 69 13.4.2.2 Sistema montado en una habitación ............................................ 70 13.4.3 Separación de físico y virtual....................................................................... 70 13.4.3.1 El mundo virtual ............................................................................. 70 13.4.3.2 El mundo físico............................................................................... 71 13.4.4 Objetos que definen la vista......................................................................... 71 13.4.5 ViewPlatform: Un lugar en el mundo virtual ............................................ 73 13.4.6 El sistema de coordenadas .......................................................................... 74 13.4.6.1 Sistema de coordenadas “montados en habitación” ................. 74 13.4.6.1.1 Sistemas de coordenadas virtuales ............................................ 74 13.4.6.1.2 Sistemas de coordenadas físicos ................................................ 75 13.4.6.2 Sistemas de coordenadas “montados en cabeza” ..................... 75 13.5 RESUMEN ................................................................................................................. 76 13.6 CONCLUSIONES ..................................................................................................... 78 13.7 BILIOGRAFÍA Y RECURSOS................................................................................ 79
3
Índice de Tablas TABLA 1 - ESCALA DE LAS COORDENADAS DE ALTA RESOLUCIÓN .................................................................... 20 TABLA 2 - REGLAS DE GENERACIÓN DE COLOR EN PRESENCIA DE UN OBJETO MATERIAL ................................. 47 TABLA 3 - REGLAS DE GENERACIÓN DE COLOR EN AUSENCIA DE UN OBJETO MATERIAL .................................. 47 TABLA 4 - TABLAS DE MOVIMIENTOS PREDEFINIDOS EN JAVA 3D .................................................................... 57
Índice de figuras FIGURA 1 - IMAGEN 3D VISTA SIGUIENDO UNA ESTRUCTURA DE ÁRBOL ............................................................. 6 FIGURA 2 - NOTACIÓN EMPLEADA EN LOS GRAFOS DE ESCENA ......................................................................... 11 FIGURA 3 - ESTRUCTURA GENERAL DE UN GRAFO DE ESCENA ........................................................................... 12 FIGURA 4 - GRAFO DE ESCENA ILEGAL .............................................................................................................. 18 FIGURA 5 - POSIBLE CORRECCIÓN DEL GRAFO DE ESCENA ILEGAL .................................................................... 19 FIGURA 6 - TIPOS DE SISTEMAS DE COORDENADAS............................................................................................ 19 FIGURA 7 - JERARQUÍA DE CLASES DEL PAQUETE JAVAX.VECMATH .................................................................. 25 FIGURA 8 - JERARQUÍA DE CLASES PARA LAS FIGURAS GEOMÉTRICAS PREDEFINIDAS ....................................... 27 FIGURA 9 - JERARQUÍA DE CLASES PARA LA CLASE GEOMETRY ........................................................................ 29 FIGURA 10 - EJEMPLO DE CREACIÓN DE UN CUBO EMPLEANDO CLASES INDEXADAS ......................................... 32 FIGURA 11 - JERARQUÍA DE CLASES DE DEFINICIÓN GEOMÉTRICA INDEXADAS ................................................. 33 FIGURA 12 - ORIENTACIÓN Y ALINEACIÓN DE UN TEXTO 3D............................................................................. 34 FIGURA 13 - LUZ (L), VECTOR NORMAL A LA SUPERFICIE (N) Y VECTOR DIRIGIDO AL OBSERVADOR (E) ......... 42 FIGURA 14 - ESFERA SOMBREADA ..................................................................................................................... 43 FIGURA 15 - EL VECTOR DE LUZ PERMANECE CONSTANTE PARA UNA FUENTE DE TIPO DIRECTIONALLIGHT ..... 43 FIGURA 16 - VARIACIÓN DEL VECTOR DIRIGIDO AL OBSERVADOR (E) ............................................................... 44 FIGURA 17 - MÉTODOS FLAT Y GOURAUD EMPLEADOS PARA SOMBREAR UNA ESFERA ..................................... 45 FIGURA 18 - COMBINACIÓN DE TEXTURA Y COLOR ........................................................................................... 51 FIGURA 19 - GRAFO DE ESCENA QUE INCORPORA UN COMPORTAMIENTO .......................................................... 55 FIGURA 20 - CLASES DE COMPORTAMIENTO IMPLICADAS EN LA INTERACCIÓN CON EL USUARIO ...................... 56 FIGURA 21 - DISCRIMINACIÓN DE UN OBJETO VISUAL MEDIANTE EL MECANISMO PICK RAY .............................. 59 FIGURA 22 - JERARQUÍA DE CLASES BEHAVIOR INVOLUCRADAS EN LA ANIMACIÓN ......................................... 60 FIGURA 23 - PULSO DE TIEMPO GENERADO POR UN OBJETO ALPHA................................................................... 61 FIGURA 24 - FORMAS ALTERNATIVAS DE ONDA GENERADAS POR UN OBJETO ALPHA ....................................... 62 FIGURA 25 - SUAVIZADO DEL PULSO DE TIEMPO GENERADO POR UN OBJETO ALPHA ........................................ 62 FIGURA 26 - RESULTADOS DE SUAVIZAR UN PULSO DE TIEMPO DE UN OBJETO ALPHA ...................................... 63 FIGURA 27 - JERARQUÍA DE CLASES DE LOS INTERPOLADORES.......................................................................... 63 FIGURA 28 - PARES KNOT/VALOR Y CRITERIO DE SELECCION DE UN KNOT ........................................................ 64
4
13.1 INTRODUCCIÓN 13.1.1 ¿Qué es Java 3D? La API (Application Program Interface) Java 3D es una interfaz de programación de aplicación utilizada para escribir aplicaciones y applets con gráficos en tres dimensiones. Proporciona a los desarrolladores constructores de alto nivel para crear y manipular geometrías 3D y para construir las estructuras utilizadas en el renderizado de dichas geometrías. Se pueden describir grandes mundos virtuales utilizando estos constructores, que proporcionan a Java 3D la suficiente información como para renderizar dichos mundos de forma eficiente. Java 3D proporciona a los desarrolladores de gráficos 3D la principal característica de Java: “escribe una vez y ejecútalo donde sea”. Java 3D es parte del conjunto de APIs JavaMedia, lo cual hace que esté disponible en un gran número de plataformas. También, se integra correctamente con Internet ya que tanto los applets como las aplicaciones escritas utilizando Java 3D tienen acceso al conjunto completo de clases de Java. La API Java 3D parte de otras APIs gráficas existentes así como de las nuevas tecnologías disponibles. Las construcciones gráficas de bajo nivel de Java 3D sintetizan las mejores ideas encontradas en otras APIs de bajo nivel como Direct3D, OpenGL, QuickDraw3D y XGL. Del mismo modo, sus construcciones de alto nivel integran las mejores características proporcionadas por varios sistemas de escenas basados en grafos. Además, Java 3D introduce algunos conceptos que no se consideran habitualmente como parte de los entornos gráficos, como el sonido espacial 3D. Las posibilidades de sonido de Java 3D permiten proporcionar una experiencia más realista al usuario.
13.1.2 Objetivos Java 3D ha sido diseñado teniendo en cuenta diferentes objetivos; prestando especial atención en el buen rendimiento. Se tomaron diferentes decisiones relativas al diseño de tal forma que las implementaciones de Java 3D proporcionaran el mejor rendimiento posible a las aplicaciones de usuario. En particular, cuando se realizan distribuciones, se elige la alternativa que permite obtener mejores prestaciones en tiempo de ejecución. Otros objetivos importantes de Java 3D son: ¾ Proporcionar un amplio conjunto de utilidades que permitan crear mundos en 3D interesantes. También se tuvo en cuenta no incluir características no esenciales u oscuras. No se incluyeron características que podrían colocarse directamente sobre Java 3D.
5
¾ Proporcionar un paradigma de programación orientado a objetos de alto nivel para permitir a los desarrolladores generar sofisticadas aplicaciones y applets de forma rápida. ¾ Proporcionar soporte a cargadores en tiempo de ejecución. Esto permite que Java 3D se adapte a un gran número de formatos de ficheros, como pueden ser formatos específicos de distintos fabricantes de CAD, formatos de intercambio o VRML 1.0 (Virtual Reality Modelling Language) y VRML 2.0.
13.1.3 Cómo ver un objeto en 3D siguiendo un grafo Java 3D distribuye la información necesaria para representar objetos y escenas en tres dimensiones en una estructura de grafo. Siguiendo dicha estructura desde el nodo raíz hasta los distintos nodos hoja, se van viendo las distintas operaciones que se realizan para crear la escena final que se quiere conseguir. En dicho grafo se incluyen tanto los distintos elementos que forman parte de la escena como las transformaciones que se les aplica. Del mismo modo, se insertan en el mismo grafo (aunque en otra rama distinta) diferentes elementos que tienen que ver con el punto de vista del usuario. La Figura 13. 1 representa cómo se puede crear una imagen compleja mediante la unión de diferentes elementos unidos por las correspondientes relaciones.
Figura 1 - Imagen 3D vista siguiendo una estructura de árbol
6
En esta figura puede apreciarse cómo, para componer la figura final (el circuito), es necesario modelar previamente las distintas partes que la forman. Alguna de las partes puede, a su vez, ser dividida en otras partes que también necesitan ser modeladas. De esta forma, para llegar a obtener la imagen global, hay que recorrer las distintas ramas generadas, desde las hojas hasta la raíz, formándose así los distintos elementos que convergen en la creación del objeto final. Al igual que en la figura, el árbol necesario para generar imágenes en Java 3D va formando los distintos elementos de las mismas de manera progresiva, añadiendo en las diferentes ramas del árbol las características propias de la imagen que se genera. Por otro lado, la distribución de los elementos que forman la escena en una estructura jerárquica permite aislar convenientemente unos aspectos de otros para poder trabajar con ellos de forma más independiente.
13.1.4 Paradigma de programación Java 3D es una API orientada a objetos. Las aplicaciones construyen los distintos elementos gráficos como objetos separados y los conectan unos con otros mediante una estructura en forma de árbol denominada grafo de escena. La aplicación manipula los diferentes objetos utilizando los métodos de acceso, de modificación y de unión definidos en su interfaz.
13.1.4.1 Modelo de programación del grafo de escena El modelo de programación basado en el grafo de escena de Java 3D proporciona un mecanismo sencillo y flexible para representar y renderizar escenas. El grafo de escena contiene una descripción completa de la escena o universo virtual. Esta descripción incluye datos sobre la geometría, información de los distintos atributos, así como información de visualización necesaria para renderizar la escena desde un punto de vista en particular. La API Java 3D mejora algunas APIs previas eliminando algunas de las serias dependencias impuestas por éstas. Java 3D permite al programador diseñar su escena en base a objetos geométricos y no considerando triángulos. Le permite centrarse en la escena y en su composición y no en cómo escribir el código para renderizar eficientemente la escena en cuestión.
13.1.4.2 Aplicaciones y applets Java 3D ni anticipa ni soporta directamente cualquier necesidad posible de 3D. En cambio, proporciona la base necesaria para añadir nuevas funcionalidades utilizando código Java. Objetos definidos utilizando un sistema de CAD o de animación se pueden incluir en una aplicación basada en Java 3D. Algunos paquetes de modelados tienen distintos formatos externos que son, en muchos casos, propietarios. Los diseñadores pueden exportar geometrías a fichero utilizando modeladores externos. Java 3D puede utilizar toda esa información geométrica, pero sólo si la aplicación proporciona un método para leer y traducir la información del modelador en primitivas Java 3D. 7
De forma similar, cargadores VRML analizarán y traducirán ficheros VRML y generarán los objetos Java 3D apropiados y el código Java necesario para poder utilizar el contenido de los ficheros. ¾ Navegadores. Los navegadores actuales pueden aceptar contenido 3D pasando información a visores 3D (plugins) que la renderizan dentro de su propia ventana. Con el tiempo, serán los propios navegadores los que se encarguen, directamente, de la gestión de los elementos 3D. ¾ Juegos. Los desarrolladores de software para juegos 3D siempre han intentado aprovechar, en la medida de lo posible, hasta el límite las posibilidades del hardware disponible. Históricamente han utilizado optimizaciones específicas del hardware y, por su puesto, no portables. De esta forma trataban de lograr el mejor rendimiento posible. Por esta razón, la programación típica de juegos se realizaba a un nivel de abstracción menor que el sencillo nivel de Java 3D. Sin embargo, la tendencia actual en la creación de juegos 3D es usar aceleradores hardware 3D de propósito general y utilizar menos “trucos” para la renderización. Así pues, aunque Java 3D no fue explícitamente diseñado para satisfacer las expectativas de los desarrolladores de juegos, sus sofisticadas técnicas de implementación proporcionan un rendimiento más que suficiente para realizar distintas aplicaciones para juegos. Puede criticarse, de cualquier forma, que las aplicaciones escritas con una API general, como puede ser Java 3D, pueden tener una ligera penalización en cuanto a rendimiento en comparación con otras que utilicen técnicas no portables. Sin embargo, otros factores como la propia portabilidad, el tiempo de desarrollo y el coste pueden también tenerse en cuenta para contrarrestar ese pequeño déficit de rendimiento.
13.1.5 Explicación de la estructura de trabajo En este documento se han tratado de explicar los conceptos básicos de Java 3D partiendo de unos ciertos conocimientos previos (no demasiados) del mundo de la informática gráfica. Se han abordado las distintas ideas centrales de Java 3D sin profundizar demasiado, pero dando suficientes referencias a manuales y ejemplos como para permitir una investigación posterior más exhaustiva. El trabajo comienza con la explicación sencilla de los conceptos más generales para profundizar posteriormente, primero en la parte relativa a la rama de contenido del grafo de escena (los distintos elementos que se pueden utilizar para componer una escena) y, posteriormente, en la rama de visualización (en la que se explican las distintas opciones de visualización que proporciona Java 3D. No se han añadido fragmentos de código ya que, aunque podrían resultar aclaratorios, alargarían demasiado el presente documento (para compensar la ausencia de
8
código, se incluye una sección de recursos en la que se pueden encontrar tanto manuales y documentación como variados ejemplos).
9
13.2 CONCEPTOS GENERALES Un universo virtual de Java 3D se crea a partir de un grafo de escena. Una definición habitual de grafo es una estructura de datos compuesta de nodos y arcos. Un nodo es un elemento de datos y un arco es una relación ente elementos de datos. Los nodos del grafo de escena se corresponden con instancias de clases Java 3D. Los arcos representan dos tipos de relaciones entre las instancias de Java 3D. La relación más habitual es la relación padre-hijo. Un nodo grupo puede tener varios hijos, pero sólo un padre. Un nodo hoja puede tener un padre, pero no hijos. La otra relación es la referencia. Una referencia asocia un objeto del tipo NodeComponent con un nodo del grafo de escena. Los objetos NodeComponent definen tanto la geometría como los atributos de apariencia que se utilizan para renderizar los objetos visuales. Los grafos de escena de Java 3D se construyen utilizando objetos Node unidos por relaciones padre-hijo formando una estructura de árbol. En una estructura de árbol, un nodo es la raíz. Se puede acceder al resto de los nodos del árbol siguiendo los arcos que parten del nodo raíz. Los arcos de un árbol no forman ciclos. Un grafo de escena está formado por árboles cuya raíz se sitúa en los objetos Locale. Los NodeComponent y los arcos de referencia no forman parte, realmente, del árbol del grafo de escena. Existe sólo un camino desde la raíz de un árbol hasta cada una de las hojas, de igual forma, sólo hay un camino desde la raíz de un grafo de escena hasta cada uno de los nodos hoja. El camino desde la raíz de un grafo de escena hasta un nodo hoja en particular se llama el camino de escena de ese nodo hoja. Por lo tanto, teniendo en cuenta la propiedad antes descrita, cada nodo hoja tiene sólo un camino de grafo de escena. Cada camino de grafo de escena en Java 3D especifica completamente la información del estado de su hoja. La información del estado incluye datos como la localización, orientación y tamaño de un objeto visual. Por lo tanto, los atributos de cada objeto visual dependen directamente de su camino de grafo de escena. El renderizador de Java 3D utiliza esta propiedad y renderiza las hojas en el orden que él determina que es más eficiente. El programador de Java 3D no tiene control sobre el orden en que se renderizan los distintos objetos. Las representaciones gráficas de los grafos de escena sirven como herramienta de desarrollo así como de documentación para los programas de Java 3D. Los grafos de escena se crean utilizando la simbología mostrada en la Figura 13.2. Los programas de Java 3D pueden tener muchos más objetos que los que se muestran en el grafo de escena. Para diseñar un universo virtual de Java 3D se dibuja un grafo de escena utilizando el conjunto habitual de símbolos. Una vez el programa se ha escrito, el grafo de escena creado es la representación precisa del programa siempre y cuando se hayan seguido las especificaciones indicadas por el mismo.
10
Figura 2 - Notación empleada en los grafos de escena
Los símbolos de la columna de la izquierda representan los distintos objetos que se usan en el grafo de escena. Los dos primeros se corresponden con objetos de clases específicas: VirtualUniverse y Locale. Los tres símbolos siguientes representan objetos de las clases Group, Leaf y NodeCompoent. Estos tres símbolos suelen llevar anotaciones para indicar la subclase a la que pertenece el objeto en cuestión. El último símbolo de la izquierda se utiliza para representar cualquier otro tipo de objeto. Por otro lado, los símbolos de la derecha representan los arcos que indican la existencia de relaciones. La flecha convencional representa una relación padre-hijo entre dos objetos. Y, la flecha sombreada, referencia otro objeto. Los objetos que son referenciados se pueden compartir entre diferentes ramas del grafo de escena.
13.2.1 Objetos del grafo de escena En la Figura 13.3, aparece el esqueleto general de un grafo de escena básico. En él aparecen prácticamente todos los elementos que se utilizan para crear un grafo de escena. Dichos elementos se enumeran a continuación y se explicarán con más detalle en los siguientes apartados del trabajo.
11
Figura 3 - Estructura general de un grafo de escena
13.2.1.1 Objetos de la superestructura del grafo de escena Java 3D define dos objetos de superestructura del grafo de escena, VirtualUniverse y Locale, que se utilizan para contener los distintos subgrafos que forman el grafo de escena. ¾ Objeto VirtualUniverse. Un objeto VirtualUniverse consiste en una lista de objetos Locale que contienen una serie de nodos del grafo de escena que existen en el universo. Normalmente, las aplicaciones sólo necesitan un universo virtual, incluso las bases de datos virtuales muy grandes. Las operaciones sobre este objeto incluyen la enumeración de los distintos objetos Locale que contiene. ¾ Objeto Locale. El objeto Locale contiene un conjunto de subgrafos del grafo de escena cuya raíz se corresponde con un nodo del tipo BranchGroup. Un objeto Locale también define la localización del universo virtual utilizando coordenadas de alta resolución (HiResCoord) para especificar la posición. El HiResCoord se utiliza como el origen de todos los objetos del grafo de escena contenidos en el Locale. Un objeto Locale no tiene padre en el grafo de escena, pero se une de forma implícita a un universo virtual cuando se construye. Un objeto Locale puede referenciar un número arbitrario de nodos BranchGroup, pero no tiene hijos explícitos. Las coordenadas de todos los objetos del grafo de escena son relativas al HiResCoord del Locale en el que se encuentran. Las operaciones del objeto Locale incluyen establecer y obtener el HiResCoord y añadir y eliminar subgrafos.
12
13.2.1.2 Objetos de agrupación de nodos Los nodos de agrupación son los elementos de unión que se utilizan para construir un grafo de escena. Todos los nodos de agrupación pueden tener un número variable de nodos hijos incluyendo otros nodos de agrupación y nodos hoja. Estos hijos tienen un índice asociado que permite realizar operaciones sobre un hijo en particular. Sin embargo, salvo que se utilice alguno de los nodos de agrupación ordenados especiales, el renderizador de Java 3D puede renderizar los hijos de un nodo de agrupación en el orden que considere más oportuno (incluso puede renderizar varios hijos en paralelo). ¾ Nodos Group. Los objetos Group son nodos de agrupación de propósito general. Tienen un solo padre y un número arbitrario de hijos. Entre las operaciones que proporciona este objeto están las de añadir, eliminar y enumerar los hijos del grupo. Las subclases de este objeto añaden semánticas adicionales. ¾ Nodos BranchGroup. Un nodo BranchGroup es la raíz de un subgrafo de una escena que puede compilarse como una unidad, unirse a un universo virtual o incluirse como hijo de un nodo de agrupación en otro subgrafo. Un subgrafo, cuya raíz sea un nodo de este tipo puede imaginarse como una unidad de compilación a la que se le pueden realizar las siguientes acciones: o Se puede compilar invocando a su método de compilación. Esta operación hará que se compile el subgrafo completo así como cualquier otro nodo de tipo BranchGroup contenido en dicho subgrafo (además de todos sus descendientes). o Se puede insertar dentro de un universo virtual conectándolo con un objeto Locale. Entonces se dice que el subgrafo completo está vivo. o Se puede desconectar el BranchGroup del subgrafo al que está contenido en tiempo de ejecución, siempre y cuando se den las condiciones necesarias para poderlo hacer (las capacidades se analizan en el apartado Concepto de límite). También se le puede cambiar de padre. Si un BranchGroup se encuentra dentro de un subgrafo, como hijo de algún otro nodo de agrupación, no se puede unir a un Locale. ¾ Nodos TransformGroup. Los nodos TransformGroup especifican una transformación espacial sencilla utilizando un objeto Transform3D que puede colocar, orientar y escalar todos sus hijos. La transformación especificada tiene que ser tal que se pueda realizar en los objetos en los que se va a aplicar. Si un nodo TransformGroup se utiliza como antecesor de un nodo ViewPlatform en el grafo de escena, entonces la transformación tiene que ser congruente, es decir, sólo se pueden realizar rotaciones, traslaciones y escalados uniformes en un camino directo desde un Locale hasta un nodo ViewPlatform. De todas formas, si se intenta realizar
13
una transformación no permitida, se generaría una excepción del tipo BadTransformException. Los efectos de las transformaciones en el grafo de escena son acumulativos. La concatenación de las transformaciones de cada TransformGroup en un camino directo desde el Locale hasta un nodo hoja define un modelo de transformación que toma los puntos de las coordenadas locales del nodo hoja y los transforma en coordenadas de mundo virtual. Este modelo de transformación se utiliza para transformar puntos, normales y distancias en coordenadas de mundo virtual.
13.2.1.3 Objetos nodos hoja Los nodos hoja (Leaf) forman una clase abstracta para todos los nodos del grafo de escena que no tienen hijos. Proporcionan enlaces espaciales y capacidades de instanciación para compartir grafos de escena. Proporcionan también una plataforma de visión para colocar y orientar los objetos en un punto de vista dentro del mundo virtual. ¾ Nodos Shape3D. La clase Shape3D da soporte a la creación de objetos geométricos. Contiene dos componentes: una referencia a la forma geométrica y a su componente de apariencia. El objeto de geometría define los datos geométricos de la forma, mientras que el objeto de apariencia especifica los atributos de apariencia del objeto como pueden ser color, material, textura, etc. ¾ Nodos ViewPlatform. Los nodos ViewPlatform definen una plataforma de visualización que se referencia mediante un objeto View. La posición, orientación y escala de las transformaciones desde el grafo de escena hasta el nodo ViewPlatform especifican la localización del punto de vista y hacia qué dirección está orientado. Un observador puede deambular por una escena cambiando las transformaciones en la jerarquía del grafo de escena por encima del ViewPlatform. ¾ Nodos Behavior. Los nodos hoja Behavior permiten que una aplicación modifique el grafo de escena en tiempo de ejecución. Behavior es una clase abstracta que define propiedades comunes a todos los objetos de comportamiento de Java 3D. Hay varios comportamientos predefinidos que son subclases de Behavior. Además, el usuario puede redefinir estos objetos si lo considera preciso. ¾ Nodo BoundingLeaf. Define una región limitada que puede ser referenciada por otros nodos para definir una región de influencia (nodos Fog y Light), una región de activación (nodos de Background, Clip y SoundScape) o una región de planificación (nodos Sound y Behavior). La región limitada se define en el sistema de coordenadas local del nodo BoundingLeaf. Se puede utilizar una referencia a este nodo en lugar de a los límites de un objeto de alguno de los nodos antes mencionados. Este nodo permite a la aplicación especificar una región limitada en un sistema de coordenadas diferente del sistema de coordenadas local del objeto que referencia los
14
límites. Es decir si, por ejemplo, en una habitación hay varias luces, los límites aplicados a las distintas luces se corresponderán siempre con la habitación, independientemente del movimiento de las propias luces. Así, utilizando un objeto de este tipo, no es necesario aplicar coordenadas de límites distintas para cada objeto de iluminación (ya que cada uno tendría su propio sistema de coordenadas), sino que todos los límites se aplicarían en función del objeto BoundingLeaf. ¾ Nodo Background. Este nodo define un fondo para la aplicación. Este fondo puede ser, bien un color fijo o una imagen que se utiliza para rellenar la ventana utilizada. También especifica a la aplicación la región en que el nodo Background está activo. Un nodo de este tipo está activo cuando la región de la aplicación intersecta con el volumen de activación del ViewPlatform. Si hay varios nodos Background activos, se utiliza el que esté más cercano al ojo, y si no hay ninguno activo, el fondo de la ventana se pinta de negro. ¾ Nodo Fog. Se trata de una clase abstracta que define un conjunto de atributos comunes que controlan la niebla de la escena. Entre dichos atributos se encuentran el color de la niebla y un objeto de límites que especifica la región de la influencia del nodo de niebla. Todos los objetos que intersectan con la región de influencia del objeto de niebla modifican su color (para aplicarle la niebla) una vez aplicadas las luces y texturas. o Nodo ExponentialFog. Extiende el nodo Fog añadiéndole una densidad de niebla que se usa como exponente de la ecuación de niebla. La densidad se define en el sistema de coordenadas local del nodo, aunque la ecuación de niebla se referirá a las coordenadas del ojo. o Nodo LinearFog. Extiende el nodo Fog añadiendo un par de valores de distancia en el eje z que indican el punto en que la niebla debe comenzar a oscurecer la escena y en el que debe oscurecerla completamente. ¾ Nodo Light. Es una clase abstracta que define las propiedades comunes a todos los nodos de luz. Cada luz tiene asociado un color, un estado (encendida o apagada) y un objeto de límites que especifica la región de influencia de la luz. El modelo de iluminación de Java 3D se basa en un subconjunto del modelo de iluminación de OpenGL. Sobre el tema de luces se vuelve en el apartado Luces. ¾ Nodo Sound. Es también una clase abstracta que define las propiedades comunes de todos los nodos de sonido. Un grafo de escena puede contener varios elementos de sonido. Cada nodo de sonido contiene una referencia a los datos de sonido, un factor de escala de amplitud, un flag que indica si el sonido asociado con el objeto debe reproducirse hasta que se acaba o sólo hasta que se desactive el objeto, el número de veces que debe repetirse, un estado (si está activado o no), una región de influencia, una prioridad, etc. Siempre que el usuario se encuentre dentro de los límites de influencia del sonido, este será potencialmente audible.
15
o Nodo BackgroundSound. Define una fuente de sonido sin atenuación que no tiene ni posición ni dirección. Tiene los mismos atributos que el nodo Sound. Se utilizan como sonidos de ambiente y puede haber varios activos a la vez. o Nodo PointSound. Define un sonido cuyas ondas se emiten en todas las direcciones desde su localización. Se añaden a los parámetros del nodo Sound, la localización y el grado de atenuación con la distancia. o Nodo ConeSound. Define un nodo PointSound cuyo sonido está dirigido a lo largo de un vector en el espacio. El sonido se atenúa tanto a lo largo como en un cierto ángulo también definido. ¾ Nodo Morph. Este nodo permite que una aplicación realice morphings entre diferentes matrices de geometría. Este nodo contiene un único nodo de apariencia y una matriz de matrices de geometría, con un peso para cada una. El nodo Morph combina todas estas matrices en una forma mezcla de todas en función del peso asignado a cada una. ¾ Nodo Link. Este nodo permite que la aplicación referencia un subgrupo compartido, cuya raíz es un nodo SharedGroup, dentro de una rama del grafo de escena. Varios nodos Link pueden referirse a un mismo nodo SharedGroup. Las nieblas, el sonido y el morphing no son objeto de este trabajo, ya que se trata de elementos que se pueden considerar avanzados dentro del mundo 3D. Para conocer más sobre estos aspectos acudir a (Sun Microsystems, 1999).
13.2.2 Otros objetos implicados Los objetos del grafo de escena analizados hasta ahora son los que realmente se consideran parte de dicho grafo de escena. Pero, además de estos nodos, existen otros que permiten incluir información adicional y esencial en dicha estructura de árbol. El primer grupo de estos elementos son los que permiten configurar la rama de visualización y que se unen al objeto ViewPlatform. Estos objetos son Canvas3D, Screen3D, View, PhysicalBody y PhysicalEnvironment. De forma breve, ya que se describirán con más detalle en el apartado 4, se comentan a continuación: ¾ View. Este es el objeto principal de visualización ya que es el que determina toda la información necesaria para generar la escena 3D. Contiene diferentes elementos del estado de visualización. ¾ Canvas3D. Es la versión 3D del objeto Canvas de AWT. Representa una ventana en la que Java 3D dibujará las imágenes. Contiene una referencia a un objeto Screen3D e información que describe el tamaño forma y localización dentro del objeto Screen3D del objeto Canvas3D.
16
¾ Screen3D. Es un objeto que contiene información relativa a las propiedades físicas de la pantalla. Java 3D separa la información relativa a la pantalla en un objeto independiente para evitar la duplicación de información sobre la pantalla, en caso de que varios objetos Canvas3D compartan una sola pantalla. ¾ PhysicalBody. Se trata de un objeto que contiene información de calibración relativa al cuerpo físico del usuario. ¾ PhysicalEnvironment. Este objeto contiene información de calibración del mundo físico. El segundo grupo de objetos adicionales son los objetos NodeComponent. Estos objetos no formar parte de la estructura de árbol, pero son esenciales para generar contenidos. De hecho, son los responsables, entre otras cosas, de que una figura tenga una cierta geometría bajo una cierta apariencia (color, textura...) Los objetos NodeComponent se asocian a través de relaciones de referencia con objetos Leaf para los cuales define la apariencia y la geometría. Las características de estos nodos se analizan con más detalle en los apartados Construcción de elementos geométricos y Modificación de apariencia.
13.2.3 Construcción de un árbol Las subclases del objeto SceneGraph son los elementos que se unen para formar los grafos de escena. El procedimiento básico para desarrollar un programa en Java 3D consiste en siete pasos: 1. 2. 3. 4.
Crear un objeto Canvas3D. Crear un objeto VirtualUniverse. Crear un objeto Locale y unirlo al objeto VirtualUniverse. Construir la rama de visualización del grafo. a. Crear un objeto View. b. Crear un objeto ViewPlatform. c. Crear un objeto PhysicalBody. d. Crear un objeto PhysicalEnvironment. e. Unir los objetos ViewPlatform, PhysicalBody, PhysicalEnvironment y Canvas3D al objeto View. 5. Construir la(s) rama(s) de contenido del grafo. 6. Compilar la(s) rama(s) del punto anterior. 7. Insertar los distintos subgrafos en el Locale. Aunque no profundiza demasiado, esta receta sí refleja el concepto fundamental de la programación en Java 3D: el grueso de la programación consiste en la creación de las distintas ramas del grafo de escena.
17
13.2.3.1 Grafos de escena ilegales Se pueden crear grafos de escena ilegales, un ejemplo de ello es la Figura 13.4. Dicho grafo de escena es ilegal porque hay dos objetos TransformGroup que tienen un mismo objeto hoja Shape3D como hijo. Un objeto hoja sólo puede tener un padre, sólo puede haber un camino desde un objeto Locale hasta un objeto hoja. Puede parecer que en la estructura de la figura se definen tres objetos del universo virtual. Si consideramos que el objeto Shape3D se reutiliza, el grafo de escena puede definir dos objetos visuales. Sin embargo, no es un árbol legal porque los arcos de relación padre-hijo no forman un árbol.
Figura 4 - Grafo de escena ilegal
En la Figura 13. 5 se muestra una posible corrección a la estructura de árbol ilegal.
18
Figura 5 - Posible corrección del grafo de escena ilegal
Un programa en Java 3D que define un grafo de escena ilegal puede compilarse, pero la imagen que define no puede generarse. Cuando se ejecuta un programa Java 3D que contiene un grafo de escena ilegal, el sistema de Java 3D detecta el problema y, entonces, genera una excepción. El programa se seguirá ejecutando, y será necesario detenerlo, pero no se generará ninguna imagen.
13.2.4 Sistema de coordenadas Los sistemas de coordenadas en Java 3D son, por defecto “diestros”, de tal forma que la parte positiva del eje de ordenadas es el sentido ascendente de la gravedad, la parte positiva del eje de abscisas es horizontal hacia la derecha y la parte positiva del eje z está dirigido hacia el observador. La unidad utilizada por defecto son los metros. En la siguiente figura, se puede ver gráficamente esta distribución.
Figura 6 - Tipos de sistemas de coordenadas
19
13.2.4.1 Coordenadas de alta resolución La representación de las coordenadas con valores en punto flotante de doble precisión, de simple precisión o incluso valores de menor precisión es suficiente para representar y mostrar escenas en tres dimensiones de gran calidad. Si nos alejamos doscientos kilómetros desde el origen de coordenadas utilizando una precisión sencilla de punto flotante, los puntos representables aparecen de alguna forma discretizados. Si lo que se pretende es llegar a distancias muy pequeñas, muy cerca del origen, aparece el mismo problema. Las coordenadas de alta resolución de Java 3D constan de 3 números de 256 bits de punto fijo, uno para cada eje. El punto fijo se encuentra en el bit 128 y el valor 1.0 se corresponde exactamente con un metro. Este sistema de coordenadas es suficiente para describir un universo tan enorme como varios cientos de billones de años luz o como para definir objetos tan pequeños como un protón. En la Tabla 13.1 se representan cuántos bits son necesarios bien por encima o por debajo del punto fijo para representar el rango que nos interese. 2n Metros 87.29 69.68 53.07 43.43 23.60 10.65 9.97 0.00 -19.93 -115.57
Unidades Universo (20 billones de años luz) Galaxia (100000 años luz) Año Luz Diámetros del Sistema Solar Diámetro de la Tierra Milla Kilómetro Metro Micra Longitud de Planck
Tabla 1 - Escala de las coordenadas de alta resolución
Los números de punto fijo de 256 bits proporcionan también la ventaja de ser capaces de representar directamente, de forma exacta, cualquier valor de precisión sencilla de punto flotante. Las coordenadas de alta resolución de Java 3D se utilizan sólo para incluir los sistemas de coordenadas tradicionales de punto flotante en un sistema de mucha mayor resolución. De esta forma se pueden crear universos de cualquier tamaño imaginable sin preocuparnos de la precisión. Las coordenadas de alta resolución se representan como números de 256 bits con signo en complemento a dos. Aunque Java 3D mantiene oculta la representación interna de las coordenadas de alta resolución, el usuario debe especificar dichas coordenadas usando matrices de enteros de 8 elementos. Java 3D trata el entero en la posición 0 como los bits más significativos y el situado en la posición 7 como los menos significativos de la
20
coordenada de alta resolución. El punto binario se localiza en el bit 128 o entre los enteros de las posiciones 3 y 4. La forma en que los cargadores de ficheros manejan las coordenadas de alta resolución depende de cada cargador en concreto, ya que Java 3D no define directamente ninguna semántica de carga de ficheros. Sin embargo, hay ciertas consideraciones que pueden indicarse. Para universos pequeños (del orden de cientos de metros), un solo Locale con coordenadas de alta resolución ubicado en la posición (0.0, 0.0, 0.0) como el nodo raíz es suficiente. Un cargador puede construir automáticamente este nodo durante el proceso de carga ya que las coordenadas de alta resolución no necesitan tener una representación directa en el fichero externo. Universos virtuales de mayor tamaño se suelen construir siguiendo la jerarquía habitual de directorios de cualquier disco duro, es decir, un universo virtual raíz que contiene la mayoría de las referencias a ficheros externos que incluyen universos virtuales. En este caso, el objeto que contiene la referencia al fichero define la localización de los datos que se tienen que leer en el universo virtual en cuestión. El contenido de los ficheros de datos debe enlazarse al nodo – fichero mientras se leen, heredando así las coordenadas de alta resolución del objeto como el nuevo universo virtual origen del grafo de escena embebido. Si ese mismo grafo de escena contiene a su vez coordenadas de alta resolución, tendrán que ser trasladadas en la cantidad que indiquen las coordenadas de alta resolución del objeto – fichero y entonces añadidas al universo virtual mayor como nuevas coordenadas de alta resolución, con todo su contenido por debajo de las mismas. A la hora de tratar con objetos que se mueven con gran amplitud, hay que considerar que tendrán que cambiar periódicamente su Locale padre de forma que se adapte más adecuadamente a sus nuevas coordenadas. Si no existiera ningún Locale suficientemente apropiado, la aplicación podría crear uno nuevo.
13.2.5 Modos de renderización Java 3D proporciona tres modos diferentes de renderización: modo inmediato, modo retenido y modo compilado-retenido. Cada modo proporciona, sucesivamente, mayor libertad para optimizar la ejecución de la aplicación. Las características de la mayor parte de las aplicaciones provocan que los dos últimos métodos sean los más utilizados. ¾ Modo inmediato. El modo inmediato no permite mucha optimización en cuanto al grafo de escena se refiere. En este modo, el nivel de abstracción de Java 3D es bastante elevado y acelera el renderizado inmediato de los objetos. Una aplicación debe proporcionar un método de dibujado con un conjunto completo de puntos, líneas o triángulos que son posteriormente renderizados por el generador de imágenes de alta velocidad de Java 3D. Por supuesto, la aplicación puede construir estas listas de puntos, líneas o triángulos en cualquier forma que elija.
21
Este modo de renderización permite la mayor flexibilidad y libertad a costa de una reducción en el rendimiento. Java 3D no dispone, en este modo, de información acerca de los objetos gráficos de la composición. Debido a esa ausencia de información, Java 3D apenas puede realizar optimizaciones en la aplicación del programador. El programador puede utilizar o no la estructura de grafo de escena heredada del diseño de Java 3D; puede elegir entre dibujar la escena directamente o definir el grafo de escena. El modo inmediato puede utilizarse tanto de forma independiente como combinado con los otros dos métodos existentes. ¾ Modo retenido. El modo retenido requiere que la aplicación construya un grafo de escena y que especifique qué elementos de dicho grafo de escena pueden cambiar durante la renderización. El grafo de escena describe los objetos del universo virtual, la distribución de dichos objetos y cómo la aplicación los anima. Este modo proporciona gran parte de la flexibilidad del modo inmediato a la vez que un incremento sustancial en la velocidad de renderización. Todos los objetos definidos en el grafo de escena son accesibles y manipulables, como lo es el grafo de escena en sí mismo. El programador puede crear grafos de escena y añadir o eliminar nodos del mismo rápidamente y ver inmediatamente los efectos de dichos cambios. Este modo permite construir objetos, insertarlos en una base de datos, componer objetos y añadir comportamientos a los objetos. Java 3D sabe que el programador ha definido objetos, sabe cómo ha combinado dichos objetos para crear objetos compuestos o grafos de escena y también conoce qué comportamientos o acciones se han añadido a los objetos. Todo este conocimiento permite a Java 3D realizar diferentes optimizaciones; puede construir estructuras de datos especiales que contengan la geometría de los objetos de tal forma que se aumente la velocidad a la que puede renderizarlo. Puede también compilar los comportamientos de los objetos para que se ejecuten a una mayor velocidad cuando sean invocados. ¾ Modo compilado-retenido. Este modo, al igual que el retenido, requiere que la aplicación construya un grafo de escena y que especifique qué elementos pueden cambiar durante la renderización. Además, la aplicación puede compilar parte o todos los subgrafos que forman el grafo de escena completo. Java 3D compila estos grafos en un formato interno. La representación compilada del grafo de escena apenas se parece a la estructura de árbol original proporcionada por la aplicación, sin embargo, es funcionalmente equivalente. Este modo es el que proporciona el mejor rendimiento.
22
Este modo permite que la API de Java 3D realice una serie de complicadas optimizaciones. Un programador puede solicitar que Java 3D compile un objeto o un grafo de escena. Un objeto o un grafo de escena compilado consiste en cualesquiera estructuras que Java 3D quiera crear para asegurar que los objetos o grafos de escena se renderizan a la máxima velocidad posible. Como Java 3D sabe que la mayor parte de los objetos o grafos de escena compilados no van a cambiar, puede realizar múltiples optimizaciones como pueden ser la fusión de múltiples objetos en un objeto conceptual, modificar un objeto para disponer de él en una geometría comprimida o incluso romper un objeto en diferentes partes y reensamblarlo en nuevos “objetos conceptuales”.
13.2.6 Paquetes Java 3D Todos los programas de Java 3D se forman, al menos parcialmente, uniendo distintos elementos de la jerarquía de clases de Java 3D. Esa gran colección de objetos describe un universo virtual, que será el que posteriormente se renderizará. La API define más de cien clases incluidas en el paquete javax.media.j3d. Estas clases son las normalmente denominadas como clases núcleo de Java 3D. Hay cientos de campos y métodos en dichas clases, sin embargo, un universo virtual sencillo que contenga algo de animación se puede construir con sólo unas pocas de ellas. Además del paquete núcleo, a la hora de desarrollar programas en Java 3D se utilizan otros paquetes. Uno de ellos es el paquete normalmente conocido como de utilidad (com.sunj3d.utils). El paquete núcleo incluye sólo las clases de nivel más bajo necesarias para programar en Java 3D. Las clases de utilidad son extensiones muy prácticas y potentes. Como era de esperar, la utilización de clases de utilidad reduce significativamente el número de líneas de código a la hora de programar. Por último, también se utilizan clases del paquete java.awt y del paquete javax.vecmath. Las clases AWT crean una ventana para mostrar la renderización. El segundo paquete define clases matemáticas de vectores para puntos, vectores, matrices y otros objetos matemáticos.
23
13.3 MODELO DE CONTENIDOS Como ya se ha visto en los apartados anteriores, un programa en Java 3D presenta una estructura de árbol con dos ramas bien diferenciadas. La primera de ellas es la rama de contenidos, que establece qué se muestra al espectador y el aspecto de dichos objetos. La otra rama es la de visualización1. Esta última determina los parámetros de visualización tales como la localización de la vista y la dirección. Para facilitar el abordar la parte de contenidos del árbol, se va a abstraer la parte correspondiente a la rama de visualización. En este apartado, se abordan los distintos mecanismos proporcionados por Java 3D para la construcción de figuras geométricas, así como otros mecanismos interesantes como los cargadores de escena. Por último, este apartado se centra en los aspectos de interacción con el usuario y animación de escenas 3D. Esta sección se complementa con una serie de ejemplos disponibles en el CD – ROM en el directorio ejemplos.
13.3.1 Sistemas de coordenadas y paquete javax.vecmath Antes de empezar a describir cómo generar contenidos dentro de un universo virtual, es necesario introducir al lector en un paquete de utilidad que permite gestionar la situación física de los elementos dentro del universo (las coordenadas dentro del sistema cartesiano), además de otros aspectos esenciales en un universo 3D (color, textura...). Este paquete se denomina javax.vecmath. Como ya se ha mencionado con anterioridad, una representación 3D no es más que una secuencia de puntos dentro de un sistema de coordenadas cartesianas. Para facilitar la forma de establecer la situación exacta de estos puntos se proporcionan las clases de este paquete. Los nombres de las clases de este paquete siguen la norma de indicar el número de componentes que necesitan y el tipo de dichas componentes (b – byte, d – double, f – float).
1
Si el lector desea ir investigando los conceptos relativos a la rama de contenidos de forma paulatina (para ellos se aconseja acudir a la bibliografía), podrá abstraerse de la rama de visualización y centrarse en la rama de contenidos gracias a una clase de utilidad que proporciona Java 3D. Esta clase es la que se denomina SimpleUniverse y se encuentra en el paquete com.sun.j3d.utils.universe. Gracias a esta clase el usuario podrá crear universos virtuales con una mínima configuración de la rama de visualización. Si lo prefiere, puede empezar por el apartado 4 y centrarse en los detalles de la rama de visualización, aunque esto no se aconseja.
24
En la figura adjunta puede verse la estructura jerárquica de clases que constituyen este paquete.
Figura 7 - Jerarquía de clases del paquete javax.vecmath
Dentro de este paquete, las clases que realmente se utilizan para la situación de elementos dentro del universo son las clases Point*2, Vector y Quat*. El resto de clases, Color*, TextCoord* permite especificar aspectos como el color y la textura3. 2
El carácter “ *” sustituye a los dos últimos caracteres del nombre de cada clase.
3
Los aspectos de color y textura se analizan más adelante en este documento.
25
Las clases del grupo denominado Point* permiten establecer la posición de cada uno de los vértices de un objeto. Además, también se utilizan para establecer puntos de luz, la localización espacial de una fuente de sonido y la posición de otros tipos de elementos. Estas clases, además, proporcionan métodos que permiten realizar operaciones habituales dentro de un espacio en tres dimensiones, tales como cálculos de distancia euclídea, distancia Manhattan... La unidad de medida es el metro. Las clases Vector* se utilizan, normalmente, para determinar superficies, ya que también se suelen utilizar para representar la dirección de una fuente de luz o una fuente de sonido. Esta clase además, proporciona métodos que facilitan las operaciones con vectores, tales como productos cruzados, normalización, cálculo del ángulo inscrito entre dos vectores... Las clases Quat* se utilizan para transformaciones de matrices avanzadas. Se ha comentado que las clases Color* y TextCoord* permiten definir aspectos de un objeto no relacionados con su posición física sino con su aspecto externo. Las clases Color* permiten definir el color y la transparencia. Las clases Color3* permiten definir en color en formato RGB. Las clases Color4* permiten, además, definir la transparencia que por defecto es opaca. Las clases TextCoord* se centra en aspectos relativos a la textura de los objetos.
13.3.2 Formas geométricas Una vez analizado uno de los mecanismos para definir puntos concretos en el espacio 3D, superficies y otros elementos como el color y la textura, se va a abordar la forma de crear objetos 3D. La forma de crear objetos visuales es mediante la clase Shape3D. Esta clase, que desciende de forma directa de la clase Leaf, puede aparecer únicamente como hoja dentro de una de las ramas del grafo de contenidos. Esta clase no contiene ninguna información a cerca de la forma o el color del objeto visual. Estos aspectos se definen a través de los objetos NodeComponent. A través de este tipo de nodos, se va a poder definir la geometría (clase Geometry y sus descendientes) y la apariencia (clase Appearance y sus descendientes) del objeto visual. Para definir un objeto 3D únicamente es necesario definir la geometría de dicho objeto, ya que se define una apariencia de forma automática. Una vez creado el objeto Shape3D y definidas sus características geométricas y de apariencia, se añade a la rama de contenidos, con lo que ya puede ser visualizado. En los siguientes apartados, se verá como utilizar los elementos geométricos predefinidos en la distribución de Java 3D, así como los mecanismos para definir la geometría de objetos 3D creado por el programador.
26
13.3.2.1 Formas geométricas predefinidas Dentro del paquete com.sun.j3d.utils.geometry se proporcionan una serie de elementos 3D comunes en universos 3D, como son cajas (Box), conos (Cone), cilindros (Cylinder) y esferas (Sphere). Existe una quinta estructura geométrica, ColorCube, que muestra un cubo con cada una de sus caras coloreadas y con efectos de luz ya establecidos. Esta clase está situada en un punto diferente de la jerarquía de objetos, de hecho es un descendiente de la clase Shape3D. Estas figuras geométricas predefinidas no son más que objetos con un NodeComponent asociado que define su geometría y que no se puede cambiar, aunque algunos de sus parámetros se pueden configurar. Ninguna de estas estructuras, salvo ColorCube, define ningún tipo de apariencia, y por lo tanto debe ser configurada por el programador. En el caso del objeto ColorCube, tanto geometría como apariencia ya están predefinidas y no pueden ser alteradas, salvo el tamaño del cubo.
Figura 8 - Jerarquía de clases para las figuras geométricas predefinidas
El objetivo de estos cinco tipos de objetos es proporcionar un mecanismo rápido para crear contenidos en tres dimensiones con poco esfuerzo de programación. Así, son muy utilizadas, sobre todo, a la hora de realizar prototipos 3D de forma rápida y simple. La clase Box define un cubo 3D de dimensiones 2metros x 2metros x 2metros cuyos vértices se localizan en (-1, -1, -1) y (1, 1, 1). Tanto las dimensiones como la situación de
27
los vértices es configurable en el momento de creación del cubo. Esta configurabilidad es una tónica para todas las figuras predefinidas aquí comentadas. La clase Cone define un cono centrado en el origen de coordenadas y alineado a lo largo del eje de ordenadas. El radio por defecto es de un metro y la altura del cono es de dos metros. Al igual que sucedía con la clase Box, tanto la altura como el radio son configurables. La clase Cylinder crea un cilindro con sus extremos cerrados y centrado en el origen de coordenadas y con su eje central a lo largo del eje ordenadas. Las dimensiones por defecto son de 1 metro para el radio y de 2 metros de altura. La clase Sphere muestra una esfera centrada en el origen y de radio 1. En la página de recursos pueden encontrarse ejemplo del uso de alguna de estas primitivas. Así en el ejemplo HelloJava3D/HelloJava3Dc.java se construye y anima un ColorCube. En el ejemplo Geometry/ConeYoyoApp.java se construye un yoyo con el uso de dos objetos Cone. El resto de primitivas se utilizan de forma muy similar.
13.3.2.2 Construcción de elementos geométricos La forma de generar contenido 3D hasta este momento se puede considerar simple pero poco potente. Para construir figuras más complejas es necesario establecer punto a punto todos los vértices que lo forman y establecer, una a una, todas sus características. De hecho, la construcción de figuras 3D complejas se basa en la construcción de triángulos, y en la disposición conjunta de éstos (básicamente, los puntos del espacio se van a agrupar en triángulos para formar volúmenes). Tanto la especificación de la localización de un punto en el espacio, como la definición de otras características (color, textura...), se realiza a través de lo que se denomina notación basada en vértices, es decir todas las características se definen mediante vectores de tres o cuatro componentes, como si de puntos del espacio se tratara. Es en este punto, donde entra en escena la clase Geometry y todas sus subclases que van a permitir este tipo de diseño, facilitando en gran medida este trabajo. El lector no debe perder de vista que estas clases son del tipo NodeComponent y que no tienen ningún sentido sino se asocian a un objeto Shape3D que es el que realmente establece el objeto visual y es el que se incluye dentro de la rama del grafo de contenidos. La jerarquía de clases, tal y como puede verse en la siguiente figura, es considerable.
28
Figura 9 - Jerarquía de clases para la clase Geometry
A continuación, se analizarán cada una de las clases. Clase GeometryArray Las subclases de esta clase van a permitir definir un conjunto de puntos, así como la forma en que esos puntos se conectan entre sí formando rectas y superficies. De esta manera, se va definiendo la morfología de la figura 3D. La clase GeometryArray es una clase abstracta, lo que significa que no puede ser instanciada de forma directa, sino que debe instanciarse alguna de sus subclases. Cuando se crea una instancia de una clase descendientes de GeometryArray, se establece como únicos parámetros, el número de vértices que va a contener el objeto GeometryArray, y la semántica de dichos puntos. Como se ha comentado en la introducción de este apartado, todas las características de un objeto se especifican a través de lo que se denomina formato de vértices (vertex format). Esto no es más que utilizar la misma notación para configurar las diferentes características de un objeto 3D. Así, existen los siguientes tipos semánticos para los vértices: 1. COORDINATES: especifica que los vértices contenidos en el vector indican situación física. 2. NORMALS: especifica que los vértices van a representar una superficie (las coordenadas definen el vector normal a dicha superficie). 3. COLOR_3 y COLOR_4: indican que los vértices identifican color sin indicar transparencia e indicando transparencia, respectivamente. 4. TEXTURE_COORDINATE_2 y TEXTURE_COORDINATE_3: textura en dos dimensiones y tres dimensiones, respectivamente.
especifican
Sobre el color y la textura se volverá en los apartados de Luces y Texturas.
29
Creada la clase, es necesario completar la estructura recién creada con los valores en formato de vértices adecuados. Para ello, la clase GeometryArray proporciona métodos adecuados para incorporar dicho contenido dependiendo del sentido semántico que se ha establecido. Un ejemplo de dichas funciones es setCoordinate(int index, Point* coordinate)4 que se utiliza habiendo, previamente, activado el bit COORDINATES. Creado el contenido, se asocia con el objeto visual (Shape3D) a través de los métodos que proporciona dicha clase. La clase GeometryArray es una clase abstracta, por lo que es necesario utilizar alguna de sus subclases. A continuación, se muestran dichas clases y su funcionamiento básico. Clases no indexadas El primer grupo de subclases, denominadas no indexadas, se caracterizan por el hecho de que cada vez que se dibuja una figura 3D las coordenadas son utilizadas una sola vez. Cada una de las subclases se diferencia del resto en la forma en la que trata la conexión de los puntos entre sí. La primera de ellas es PointArray. Esta clase considera cada uno de los puntos de forma independiente sin considerar ninguna conexión entre ellos. La clase LineArray, por el contrario, sí considera conexión entre los puntos. Considera parejas de puntos y los conecta. Cada punto únicamente puede estar conectado con otro punto. Así, si se considera cada par de puntos conectados por una recta como un conjunto, todos los conjuntos son disjuntos dos a dos. Si {v0,…, v5} son los puntos, las rectas formadas son aquellas limitadas por los pares de puntos {v0, v1}, {v2, v3}, {v4, v5}. Para ver como considera dichas parejas acuda a la Figura 13. 6. Se puede ver un ejemplo del uso de esta clase en Geometry/AxisApp.java. La clase TriangleArray considera grupos de tres puntos para construir triángulos. Al igual que sucedía con la clase LineArray, cada punto puede únicamente pertenecer a un triángulo. Si se considera el mismo conjunto de puntos que en el caso anterior los triángulos que se forma son aquellos cuyos vértices son {v0, v1, v2}, {v3, v4, v5}. Su uso es muy similar al de la clase LineArray. La clase QuadArray considera grupos de cuatro puntos para construir cuadriláteros. Como en los casos anteriores dichos cuadriláteros son disjuntos con respecto al resto. Tanto los triángulos formados mediante la clase TriangleArray como los cuadriláteros formados mediante el uso de la clase QuadArray están rellenos por defecto.
4
Acudir a (Sun Microsystems, 1999) para ver el resto de funciones.
30
La clase GeometryStripArray altera la forma de conexión de los puntos. Esta clase es abstracta con lo que es necesario hacer uso de sus subclases LineStripArray, TriangleStripArray y TriangleFanArray. El objetivo de estas clases es la construcción de elementos donde la reutilización de puntos sea un aspecto crucial en su diseño. De esta manera, van a permitir construir líneas y superficies compuestas. Haciendo un paralelismo con las clases anteriores, la clase LineStripArray se puede asemejar a la clase LineArray salvo por el hecho de que el extremo de la recta anterior sirve de origen para la recta siguiente. Así, considerando el conjunto de seis puntos, las líneas formadas por la clase LineStripArray son las siguientes {v0, v1}, {v1, v2}, {v2, v3}, {v3, v4}, {v4, v5}. La clase TriangleStripArray forma triángulos con los puntos de forma que los dos últimos vértices utilizados para formar el triángulo anterior son utilizados para construir el siguiente triángulo. La clase TriangleFanArray posee un comportamiento ligeramente diferente a TriangleStripArray. Considera el primero de los puntos como el vértice superior de todos los triángulos. El efecto final se asemeja a un “abanico” (fan), que puede observarse en la Figura 13.11. Un ejemplo de su utilización se puede ver en el ejemplo Geometry/YoyoLineApp.java donde se crea un yoyo con esta clase. Este ejemplo también incluye aspectos relativos con la modificación de la apariencia por defecto. El tema de la apariencia se aborda en el apartado Apariencia. En la construcción de objetos de cualquiera de las clases derivadas de GeometryStripArray, se aprecian diferencias con respecto a la forma de crear los objetos GeometryArray básicos. En este caso, además de establecer el número de vértices y el sentido semántico de dichos vértices, existe un tercer parámetro que establece el número de grupos de conexión (strips) que pueden construirse. Cada componente indica el número de vértices que van a formar parte de cada grupo. Por supuesto, la suma de componentes de este vector debe ser igual al número de vértices indicados en el primer parámetro. Este constructor se puede observar en el ejemplo anteriormente indicado. Clases indexadas El primer grupo de clases se caracteriza por no reutilizar ninguno de sus vértices cada ver que se redibuja la figura. Únicamente las clases derivadas de GeometryStripArray reutilizan parcialmente los vértices que contienen. Por el contrario, las clases derivadas de IndexedGeometryArray proporcionan un nivel más de indirección. Esto permite reutilizar los vértices, de forma independiente a su situación física dentro del vector de puntos proporcionado. Para efectos de la comprensión de estas clases, se van a diferenciar los vectores de puntos que utilizan en dos grupos: los vectores de datos y los vectores de índices. Los primeros hacen referencia a los tipos que ya se han visto hasta ahora. Son los que contienen 31
los puntos que identifican coordenadas, color, textura... Los vectores de índices contienen referencias a los vectores de datos. Dentro de estos últimos, existen cuatro tipos: los índices de coordenadas, los de color, superficie y de textura. Nótese que existen tantos tipos de índices como tipos de vectores de datos. El número de vectores de índices coincide con el de vectores de datos y el número de componentes dentro de cada vector de índices es, normalmente, mayor que el número de componentes de los vectores de datos. Un vector de índices podría tener, en un momento dado, múltiples referencias al mismo vértice en los vectores de datos. Así, un vector de índices determina el orden de procesamiento de los datos en los vectores de datos a la hora de mostrar la geometría de la imagen 3D. Para comprender cómo funciona, considérese el ejemplo de un cubo. En este caso los vértices de dicha figura se pueden reutilizar a la hora de dibujar cada cara.
Figura 10 - Ejemplo de creación de un cubo empleando clases indexadas
El problema principal de utilización de este tipo de clases indexadas es el rendimiento. Así, son muy útiles en entornos donde aspectos como la velocidad y la memoria no son críticos. La clase IndexedGeometryArray es una clase abstracta. A partir de ésta, surgen una serie de subclases que sí pueden ser utilizadas. Estas clases son las que se muestran en la figura adjunta.
32
Figura 11 - Jerarquía de clases de definición geométrica indexadas
Como puede observarse existe la clase indexada equivalente a la clase no indexada. El funcionamiento de las clases indexadas, de cara al usuario, es el mismo que el de su equivalente no indexada, pero la forma de trabajo interna es distinta. Otras clases Un tercer grupo de clase relacionadas con la generación de elementos geométrico es el formado por las clases Raster, CompressedGeometry y Text3D. Esta última clase se analiza en el apartado Texto 2D y 3D. Las otras dos clases se describen de forma breve a continuación. Las otras dos clases quedan fuera del alcance de este documento. Para más información acudir a (Sun Microsystems, 1999).
13.3.2.3 Texto 2D y 3D Aunque el texto en sí no se puede considerar una forma geométrica, sí es una forma de incorporar contenido a una escena 3D, y no sólo eso, sino que es un elemento habitual en universos en tres dimensiones. En este apartado, se mostrará cómo incorporar texto en un universo 3D y cómo configurar alguno de sus parámetros. Java 3D considera el texto 2D y 3D de formas diferentes. Mientras el primero es un objeto descendiente de Shape3D, y por lo tanto, directamente incorporable al grafo de contenidos, el texto 3D es un NodeComponent y, como tal, necesita de la definición de un objeto Shape3D para poder utilizarlo. La clase que da soporte al texto 2D es la clase Text2D presente en el paquete com.sun.j3d.utils.geometry. Esta clase permite definir no sólo el texto que se desea que aparezca, sino otros aspectos como color, tipo de fuente, tamaño de la fuente y formato de dicha fuente. Creado el texto 2D, únicamente queda añadirlo al grafo de escena. Un ejemplo de uso de texto en dos dimensiones se puede encontrar en easyContent/Text2Dapp.java5.
5
Este ejemplo incluye elementos de animación. La animación se trata en el apartado Movimiento en Java 3D.
33
En cuanto al texto 3D, éste presenta ciertas características adicionales respecto al texto 2D que requieren más atención. En primer lugar, el texto 3D está pensado como un NodeComponent y como tal se debe incorporar a un objeto Shape3D. Para incorporar texto en tres dimensiones son necesarias dos clases adicionales: la clase Font3D y la clase Text3D. La clase Font3D permite crear una instancia de una fuentes estándar en una fuente en tres dimensiones. A la fuente planta se le añade una extrusión, es decir profundidad a través del objeto FontExtrusion. Una vez creada la fuente 3D, se crea la instancia de la clase Text3D. En el momento de creación de esta instancia se establece el objeto Font3D anteriormente creado, así como el texto que se desea mostrar. Además, a través de la clase Text3D se pueden especificar otros aspectos del texto 3D que se desea mostrar. Estas características son la posición y el punto de referencia. La posición se refiere al punto concreto dentro del espacio donde se sitúa el punto de referencia. El punto de referencia establece el punto de origen del objeto. La orientación y la alineación definen el punto de referencia. En la siguiente figura se observa el efecto de cada uno de los parámetros.
Figura 12 - Orientación y alineación de un texto 3D
El uso de texto 3D se puede ver en la aplicación easyContent/Text3Dapp.java.
13.3.2.4 Ayudas a la construcción de figuras geométricas Para crear una figura geométrica es necesario establecer cada uno de los puntos que va a ocupar en el espacio, y luego generar superficies utilizando dichos puntos (las superficies son normalmente triángulos). Se ha visto como este trabajo se realiza de forma sencilla a través de las clases descendientes de GeometryArray. Aún así, la creación de una figura puede llegar a ser una labor ardua y muy compleja. Para facilitar un poco el trabajo, el API de Java 3D proporciona un conjunto de clases de utilidad que, a partir del contorno de la
34
figura a construir, realizan los cálculos necesarios para, por ejemplo, generar los triángulos necesarios para formar el resto de la figura. Estas clases se encuentran en el paquete com.sun.j3d.utils.geometry. La clase GeometryInfo funciona como un contenedor de puntos con una determinada connotación semántica. Cuando se define un objeto de este tipo, se establece la naturaleza de las superficies a construir con dichos puntos. Así, a través de una serie de flags, se define si se construirán polígonos (POLYGON_ARRAY), si se construirán cuadriláteros (QUAD_ARRAY) o triángulos (TRIANGLE_ARRAY, TRIANGLE_STRIP_ARRAY, TRIANGLE_FAN_ARRAY). A través de los métodos adecuados se introducen, en la instancia de GeometryInfo las coordenadas de los puntos. Una vez creada una instancia de la clase GeometryInfo el uso de otras clases van a permitir realizar nuevas transformaciones sobre los puntos especificados en la primera. Estas clases son la clase Triangulator, NormalGenerator y Stripifier. Todas ellas van a tomar como referencia una instancia de la clase GeometryInfo para realizar nuevas operaciones sobre la matriz de puntos. La clase Triangulator permite convertir cualquier tipo de polígonos en triángulos que Java 3D puede procesar. Esta clase trabaja sólo en aquellas circunstancias en las que la clase GeometryInfo se define utilizando el flag POLYGON_ARRAY. La clase NormalGenerator se encarga de calcular y rellenar superficies normales a partir de los puntos del objeto GeometryInfo. Esta transformación se basa en el uso de datos indexados. En el caso de que los puntos proporcionados por GeometryInfo no presenten esta estructura, se genera el índice adecuado. Al contrario que la clase Triangulator, la clase NormalGenerator puede utilizarse de forma independiente del flag elegido. La clase Stripifier analiza los triángulos contenidos en el vector de datos de GeometryInfo y los convierte en una estructura de triángulos similar a la obtenida con la clase TriangleStripArray. Como consecuencia, se obtiene una estructura de triángulos más optimizada que con la clase Triangulator. Normalmente, para mejorar el funcionamiento de la clase Stripifier, esta transformación se combina con la clase NormalGenerator. Los pasos descritos en este apartado así como el uso de las distintas clases se puede ver en la aplicación easyContent/GeometryInfoApp.java.
13.3.2.5 Cargadores de escenas 3D Existe una gran variedad de programas que permiten generar contenidos en tres dimensiones y almacenar dicho contenido en un fichero para su posterior utilización. Programas de este estilo son 3D-Studio, Autocad... Java 3D proporciona como parte de su API un conjunto de utilidades (loaders) que van a permitir incluir el contenido de los ficheros generados por otras aplicaciones en
35
universos virtuales. Este conjunto de utilidades se encuentra en el paquete com.sun.j3d.loaders. Como ya habrá intuido el lector esto abre las puertas a una forma de generar contenido 3D mucho más potente y más sencilla. La dificultad de generar figuras en 3D está en distribuir, de forma correcta, los puntos en el espacio. En el caso de aplicaciones simples, este problema no es un gran inconveniente, pero a medida que las escenas se complican, la tarea de situar cada punto puede llegar a ser una tarea tediosa, e incluso intratable. Por lo tanto, si se pudiera disponer de herramientas de diseño 3D avanzado para construir las figuras 3D y luego importar dichas figuras, las escenas que se podrían conseguir sólo estarían limitadas por la imaginación del programador. En realidad, estos cargadores de escenas no forman parte del API de Java 3D, sino que, simplemente, Java 3D proporciona los mecanismos para su construcción. Es decir, sólo especifican la interfaz de dichos cargadores, sin establecer cómo deben implementarse. El número de cargadores disponibles es bastante considerable, y mucho de ellos de libre distribución. Java 3D proporciona un ejemplo de cargador ya implementado para el formato “.obj”. Este cargador está disponible a través de la clase ObjectFile en el paquete com.sun.j3d.loaders.objectfile. Además Java 3D va a permitir no sólo cargar una escena completa de un fichero externo, sino partes de dicha escena, se puede especificar que únicamente se carguen ciertos efectos de luz, nieblas... o incluso combinar varios ficheros externos para formar una misma escena. La potencia que se puede conseguir sólo depende de la implementación del cargador que se esté utilizando y de la propia especificación del fichero que se está procesando6. Las clases e interfaces que dan soporte a esta tecnología son los siguientes: ¾ Loader. Esta interfaz define una serie de métodos que permiten determinar la localización del fichero desde el cual cargar la escena, así como un conjunto de flags que determina que elementos del fichero se desean cargar. Algunos de estos flags son: LOAD_ALL que permite cargar todo el fichero; LOAD_BACKGROUND_NODES que permite cargar únicamente los elementos que configuran el fondo; LOAD_LIGTH_NODES que determina que sólo se cargarán los elementos de luz, etc. ¾ Scene. Esta interfaz define un conjunto de métodos que serán los encargados de extraer las características de la escena cargada desde el fichero. ¾ LoaderBase. Esta clase implementa la interfaz Loader. Los autores de cargadores extienden esta clase como paso previo a la construcción de sus propiso cargadores. 6
Si el fichero externo no especifica contenido sobre luces, sonido..., este tipo de contenidos no se podrá cargar.
36
¾ SceneBase. Esta clase implementa la interfaz Scene. Esta clase implementa un conjunto de métodos que permiten recuperar cada uno de los nodos que forman la escena cargada desde el fichero. Así, por ejemplo, cuenta con métodos como getBackgroundNodes() que permite recuperar un vector con todos los nodos que forman el fondo de la escena.
13.3.3 Modificación de la apariencia En el apartado anterior, se ha analizado diferentes formas de construcción de figuras geométricas. Dejando a un lado las figuras geométricas preestablecidas, se ha visto como el mecanismo de trabajo es crea un objeto del tipo NodeComponent que contenga la información geométrica para dibujar la figura en tres dimensiones. Esta forma de trabajo se continúa para establecer efectos de apariencia en las figuras, es decir, se crea un objeto de la clase anterior que contendrá la información necesaria para configurar la apariencia de las figuras. En este apartado, se analiza como realizar dichas operaciones de cambio de apariencia, tanto a nivel de una figura concreta, como a nivel de toda una escena.
13.3.3.1 Concepto de límite En muchos aspectos dentro de Java 3D (luces, comportamiento, configuración del fondo...) se utilizan límites o rangos. Los límites (bounds) van a permitir al programador flexibilizar acciones, apariencia..., limitando las regiones de influencia de determinados elementos. Un límite permite definir un área en la cual un determinado elemento tiene influencia. En implementación, existe una clase general denominada Bounds que permite incluir dentro de un grafo de escena el concepto de límite. Una instancia de esta clase se enlaza con un objeto del grafo de escena. Así, cada vez que el objeto del grafo de escena se desplace, el objeto Bounds irá con él. En otros casos, los objetos Bounds tendrán autonomía de movimiento7. La forma más común de determinar los límites de influencia de un determinado elemento es mediante la definición de una esfera de cierto tamaño. Esta forma de trabajo es lógica ya que la esfera es la figura geométrica más adecuada para establecer una región dentro de un mundo en tres dimensiones. La forma de definir dicha esfera es a través de la clase BoundingSphere. Aunque, no es la única manera. Existen clases que permiten definir los límites en base a figuras que no son una esfera, como son BoundingBox y BoundingPolytope. Como ejemplo ilustrativo del concepto de límite, considérese una escena en la que existe una serie de elementos en movimiento y un punto de luz fijo que ilumina todos los 7
Que el objeto Bound tenga libertad de movimiento o dependa de un objeto del grafo de escena, dependerá del propósito a conseguir.
37
objetos. Para que la luz afecte a todos los objetos en movimiento, el alcance de dicha luz debería ser lo suficientemente grande para que todos los objetos estuvieran dentro de sus límites. El tamaño de la zona de influencia se puede definir a través de los métodos proporcionados por la clase Bounds y sus descendientes. Además de la clase Bounds, existe una clase adicional que permite el control de límites. Esta clase es la clase BoundingLeaf. Esta clase extiende la clase Leaf. La diferencia con respecto a la clase Bounds, es que la clase BoundingLeaf se puede incorporar como un nodo hoja al grafo de escena funcionando de forma independiente. El objeto (u objetos) sobre el que se vaya a definir una región de influencia podrá hacer referencia a dicho BoundingLeaf. Se volverá sobre el concepto de límite en el apartado Luces. Si se desea saber más sobre dicho conceptos y su uso, se recomienda acudir al capítulo 6 de (J. Bouvier, 1999).
13.3.3.2 Configuración del fondo Aunque el formato del fondo no es un elemento que afecte a una figura en especial, es un elemento que permite alterar el aspecto de toda la escena, por lo que se ha optado por discutirlo en este punto. Por defecto, el color de fondo predeterminado por defecto para este objeto es negro. Java 3D proporciona los mecanismos necesarios para cambiar el color de fondo, o si el usuario lo prefiere, añadir imágenes como fondo e incluso formas geométricas o una combinación de los elementos anteriores. Incluso es posible definir diferentes fondos para diferentes secciones dentro de un mismo universo virtual. La clase que se encarga de gestionar el fondo es la clase Background. Esta clase hereda de forma directa de la clase Leaf. Como consecuencia, las instancias de la clase Background podrán añadirse directamente como terminación de una rama del grafo de escena, como si de una figura 3D habitual se tratara. Para crear un nuevo fondo, se deben seguir los siguientes pasos generales: 1. Se crea el objeto Background y se define el color de fondo o la imagen que va a constituirse como fondo. 2. Se añade un elemento geométrico si se desea que una figura geométrica forme parte del fondo. Este punto es opcional en el proceso de construcción de un fondo. 3. Se proporcionan los límites del fondo. 4. Se añade como hoja al grafo de escena. Para cambiar el color de fondo o incluir una imagen, la clase Background proporciona las funciones necesarias para tal cometido. Dichas clases toman como parámetro el color (en formato RGB) o un objeto que encapsula la imagen (ImageComponent2D) y actualizan el fondo. En cambio, para el segundo punto, la cosa se complica, no por la forma de incluirlo en el fondo, ya que existe la correspondiente función para ello, sino por la construcción en
38
sí de la figura geométrica. En el ejemplo easyContent/BackgroundApp.java se puede observar la inclusión de figuras geométricas como fondo de la escena. Se han utilizado objetos PointArray para simular estrellas y una clase LineArray para simular una constelación. Además, este ejemplo es un buen punto de referencia para conocer más a fondo el uso de las clases BoundingSphere y k, esta última aplicada a aspectos de interacción con el usuario8.
13.3.3.3 Apariencia Analizada la forma de alterar el fondo de una escena 3D, queda profundizar en cómo cambiar la apariencia de cada uno del resto de los elementos que forman el universo virtual. Como ya se ha podido observar, la apariencia no es un elemento que condicione la creación de universos virtuales, y de hecho, se presenta como algo adicional. Todas las formas 3D tienen definida por defecto una apariencia. Por otro lado, se ha visto como, sin necesidad de definir un nodo Appearance explícito, se pueden definir efectos de color y textura a través de las clases específicas para definir geometría9. Sin embargo, para otros muchos casos es necesario un objeto explícito que realice el trabajo. La clase Appearance es descendiente de NodeComponent y por lo tanto deberá estar relacionada con un objeto Shape3D ya que, de forma directa, no se puede incluir en el grafo de escena. Un objeto del tipo Appearance no contiene ningún tipo de información acerca de cómo se debe mostrar una figura, pero si conoce dónde buscar dicha información. Mantiene un conjunto de referencias a otras instancias de clases descendientes de la clase NodeComponent, las cuales sí tiene la información necesaria. Este último conjunto de clases se conoce como atributos de apariencia e incluyen las siguientes clases: ¾ PointAttributes. Atributos relativos a cómo se mostrarán los puntos. ¾ LineAttributes. Establece las características de visualización de una recta. ¾ PolygonAttributes. Define las características para los polígonos.
8
La interacción con el usuario se aborda en el apartado Movimiento en Java 3D.
9
Las clases descendientes de la clase Geometry permitían definir un conjunto de puntos así como su significado semántico. Dentro del rango de significados semánticos soportados estaban los siguientes: COLOR_3, COLOR_4, TEXTURE_COORDINATE_2 y TEXTURE_COORDINATE_3.
39
¾ ColoringAttributes. Establece detalles relativos al color. ¾ TransparencyAttributes. Atributos relativos a efectos de transparencia. ¾ RenderingAtributes. Permite controlar dos aspectos relacionados en el proceso de visualización de un píxel: la gestión del buffer de dibujo y la función alfa. Por esta razón, permite definir aspectos de visualización aplicables a todos los tipos de primitivas. ¾ Material. Esta clase de atributos está relacionada con los efectos de luz que se describen más adelante en este documento. ¾ TextureAttributes, Texture y TexCoordGeneration. Las tres clases están relacionadas con la gestión de texturas. Estas clases se analizan más adelante en el documento (apartado de texturas). La clase Appearance proporciona los métodos necesarios para incluir las referencias a cada una de las instancias de las clases vistas. A continuación se describen cada una de las clases con más detalle. Para su explicación se agrupan en tres secciones. La primera agrupa las clases relativas a atributos de apariencia generales, y las siguientes abordan el tema de las luces y las texturas. 13.3.3.3.1 Atributos generales PointAttributes Esta clase define los atributos que establecen cómo se mostrarán cada uno de los puntos que formar la figura. Por defecto, cada punto se corresponde directamente con un píxel. Aumentar el tamaño del punto supone aumentar el número de píxeles asociados a dicho punto. Este aumento de tamaño, a través de métodos proporcionados por la propia clase, supone acentuar la forma cuadrada que presenta el punto. Para suavizar esta forma, la clase PointAttribute proporciona un método, setPointAntialiasingEnabled(), que permite cambiar el color de los píxeles de los extremos que forman el punto, dando sensación de redondez. LineAttributes Esta clase define las características de visualización que presentarán las rectas. Concretamente, afecta a la forma en la que se mostrarán las rectas en tres sentidos: ¾ Permite definir el cuerpo de la línea, estableciendo si es sólido, intermitente, a puntos o mixto. En una palabra, define como cada uno de los píxeles que forman la recta se deben dibujar. Este aspecto de una recta se denomina patrón de la recta. ¾ Otra característica que define es el ancho de la línea, es decir el ancho de cada píxel que forma la recta.
40
¾ El tercer aspecto que permite definir es el conocido como antiálias (antialiasing), permitiendo mostrar un aspecto más suave en el dibujo de la recta. PolygonAttributes En cuanto a la visualización de polígonos se pueden parametrizar los siguientes aspectos: ¾ Se puede definir la forma en la que se mostrará el polígono: relleno, sin relleno mostrando su superficie mediante líneas que se cortan (a modo de entramado) o mostrando únicamente su perfil. Si se muestra siguiendo los dos últimos formatos especificados, los atributos del polígono también se ven afectados por las clases PointAttributes y LineAttributes. El aspecto del polígono se denomina el modo del polígono. ¾ Otro aspecto que permite configurar es si el polígono se muestra completo o no (culled). Se puede definir que caras del polígono se van a mostrar, si sólo las de la parte frontal o las de la parte posterior. Esto permite aumentar el rendimiento al mostrarse únicamente la mitad de las caras que forman un polígono. Un ejemplo de la utilización de esta clase para alterar la apariencia de un objeto se puede ver en los ejemplos geometry/YoyoLineApp.java y geometry/YoyoPointApp.java. ColoringAttributes Permiten determinar y controlar cómo se colorea la figura correspondiente. El color como en otras ocasiones se define siguiendo la notación RGB o mediante la clase Color3f. También, permite definir como se extenderá el color definido al resto de la figura por ejemplo si se trata de un polígono o una recta. Como se vio en el apartado Construcción de elementos geométricos los colores también se pueden definir por cada vértice en las clases derivadas de Geometry sin más que definir que el vector de puntos especificado identifica color. En el caso que se haya especificado color, tanto a través de la clase Geometry como a través de los atributos de color, la definición realizada sobre aquella prevalece sobre la segunda forma de definir el color. Se volverá sobre el tema del color en el apartado Luces. TransparencyAttributes Permite controlar la opacidad de una figura. Define si una figura tiene cierta transparencia así como el método elegido para generar dicho efecto de transparencia. Esta propiedad varía en una escala numérica desde 0.0, que indica que es un cuerpo opaco, y 1.0, que indica que el objeto es totalmente transparente RenderingAttributes Esta clase define un conjunto de flags que permiten configurar las características relativas al tamaño del buffer de dibujo y a la función alfa entre otros aspectos. Acudir a (Sun 41
Microsystems, 1999) para una mayor descripción de cada uno de los flags y de los diferentes métodos que permiten utilizar dichos flags.
13.3.3.4 Luces La mayor parte del modelo de luces y sombras de Java 3D está basado en OpenGL, por lo que se puede consultar más información en los temas 7 y 8 de esta asignatura. 13.3.3.4.1 Modelos implicados Para incluir efectos de luz dentro de un universo virtual, Java 3D trabaja con tres modelos específicos: modelo de luz (Lighting Model), modelo de color (Color Model) y modelo de sombreado (Shade Model). A continuación se describen de forma breve. Lighting Model Java 3D utiliza este modelo para mostrar los objetos con una mayor realidad, ya que el color de los objetos se percibe como una combinación de las propiedades físicas del objeto, de las características de las fuentes emisoras de luz, de la posición respecto a ellas y del ángulo desde el que se observa el objeto. La ecuación con la que se trabaja en este modelo se basa en tres vectores: vector normal a la superficie del vértice (N), vector dirigido a la fuente de luz (L) y el vector dirigido al observador (E). En la figura inferior se muestra como cada vértice de la esfera potencialmente se puede representar con una sombra diferente.
Figura 13 - Luz (L), vector normal a la superficie (N) y vector dirigido al observador (E)
Este modelo permite representar en un universo virtual tres tipos de reflexiones de luz presentes en el mundo real. La reflexión ambiental que mantiene un bajo nivel de luz, la difusión que es la reflexión natural de la luz sobre un objeto y la reflexión especular que creo zonas con una mayor iluminación del objeto. En la figura que tenemos a continuación, se muestra lo expuesto anteriormente, de manera que la parte más oscura de la esfera exhibe sólo la reflexión ambiente, el centro está iluminado por la luz difusa y ambiente y la parte más brillante de la esfera es el resultado de la reflexión especular con reflexiones ambiente y difusa.
42
Figura 14 - Esfera sombreada
Como se ha visto el tratamiento de la luz por parte de Java 3D es bastante complejo y si cada punto del objeto contiene un nivel de luz distinto una porción significativa del cálculo de representación se utiliza para estos vértices sombreados. Esto se puede evitar si el vector L o el vector E son constantes. Para conseguir que el vector L sea constante se debe usar una fuente DirectionalLight que proporciona una sola dirección al brillo de la luz. Esta clase proporciona tres constructores en los que se puede especificar el color, la dirección y el estado. Tal y omo se observa en la figura, al ser todos los vectores de luz de una fuente DirectionalLight paralelos la luz no se atenúa, es decir, la intensidad de la fuente no varía con la distancia al objeto.
Figura 15 - El vector de luz permanece constante para una fuente de tipo DirectionalLight
El vector E, también conocido como vector de ojo infinito, es constante por defecto, aunque podemos especificar un vector variable del ojo usando un método del objeto View. Si nos fijamos en la figura siguiente se ve como en la ventana de la izquierda que tiene un vector E constante hace que las reflexiones especulares están básicamente en la misma posición para cada esfera al contrario que en la ventana de la derecha. El objeto View contiene todos los parámetros necesarios para renderizar una escena tridimensional desde un punto de vista.
43
Figura 16 - variación del vector dirigido al observador (E)
El tiempo real para renderizar además de variar con los vectores L y E varía con el sistema utilizado. La diferencia es más pronunciada en los sistemas que renderizan por software. Para concluir este apartado hay que decir que en este modelo los fenómenos físicos complejos no se modelan, ya que en la figura anterior vemos como falta la sombra de la esfera, la luz de la esfera sobre el plano… porque para reducir la complejidad del cálculo, el modelo de iluminación considera solamente un objeto visual al mismo tiempo. Color Model En la realidad el color es una combinación de muchas longitudes de onda de la luz pero en el mundo virtual de Java 3D un solo color de luz queda especificado por una combinación de rojo, verde y azul. Es el conocido modelo de color RGB que representa muchos colores, pero no todos. El modelo de iluminación es un modelo físico, mientras que el modelo de color es una adaptación. Shade Model Es el encargado de dar sombra y color a todos los vértices que se encuentran bajo un punto de luz. Existen varios métodos para sombrear una figura, por un lado el sombreado Gouraud en el que cada píxel se sombrea con un valor derivado de la interpolación trilinear del valor de la sombra en cada vértice del polígono que lo encierra y por otro, el sombreado plano en el que a todos los píxeles de un polígono se les asigna el valor de la sobra a partir de un vértice del polígono. El primero tiene como ventaja la apariencia visual y el segundo la velocidad en la representación del software.
44
Figura 17 - Métodos Flat y Gouraud empleados para sombrear una esfera
Tanto este modelo como el modelo de luz están basados en OpenGL10. 13.3.3.4.2 Fuentes de luz El primer elemento indispensable para incluir luz en una escena es una fuente luminosa. Para ello, Java 3D proporciona toda una estructura de clases encargadas de tal cometido. Las clases definidas como elementos luminosos son descendientes de la clase Leaf y por lo tanto se pueden incluir de forma directa en el grafo de escena. Estas clases son las que se definen a continuación de forma breve. La clase principal es la clase Light. Es una clase abstracta que define los parámetros principales de la luz como son el estado (encendido o apagado), el color y los límites de influencia. Heredando de esta clase se encuentran clases más específicas que permiten incluir ciertos tipos de luz concretos: ¾ AmbientLight. Los objetos de luz ambiente proporcionan luz de la misma intensidad en todas las direcciones y modelan la luz reflejada desde otros objetos visuales. Mientras que podría ser natural pensar que una fuente de luz ambiente se puede aplicar globalmente, esto no es necesariamente cierto en un programa Java 3D. La influencia de la fuente AmbientLight está controlada por sus límites igual que otras fuentes de luz Java 3D. Se pueden utilizar varios objetos fuente AmbientLight en un programa de Java 3D. No hay límite en el número de los objetos fuentes AmbientLight que se pueden utilizar. ¾ DirectionalLight. Al contrario que las anteriores estas fuentes proporcionan una sola dirección al brillo de luz. Para los objetos iluminados con esta fuente el vector de luz es constante. Estas fuentes solo participan en las porciones difusas y specular de la reflexión del modelo de iluminación. ¾ PointLight. Es lo contrario de una fuente DirectionalLight. Define una fuente de luz colocada en algún punto del espacio y que emite luz en todas direcciones. La intensidad se atenúa con la distancia. 10
Dado que se apoya sobre OpenGL se aconseja acudir a bibliografía sobre esta librería gráfica para ampliar conceptos sobre los distintos modelos implicados (Wright et al., 1997).
45
¾ SpotLight. Es una subclase de PointLight que agrega dirección y concentración a los parámetros de posición y atenuación. La intensidad de la luz producida por una fuente de este tipo produce la luz dentro de un ángulo especificado desde la dirección de la luz. El ángulo de extensión de un objeto SpotLight podría hacer que la luz iluminara parte de un objeto visual, por lo que esta es la única luz capaz de iluminar solamente una parte de un objeto. El número de luces y los atributos de éstas es más bien una consideración artística que científica, pero a continuación se van a dar unas pautas generales. A menudo es suficiente tener solo dos luces para una escena dada, una que proporcione la iluminación principal y la otra se utiliza para completar la cara más oscura de los objetos. La luz principal normalmente se coloca a la derecha del espectador mientras que el relleno a la izquierda. Normalmente se prefiere incluir fuentes de luz direccionales para la mayoría de las aplicaciones puesto que el cálculo requerido en la representación es perceptiblemente menor que para los puntos de luz. Las fuentes de puntos de luz se usan muy raramente debido a la alta complejidad de cálculo. La influencia de una luz va a determinar que objetos se ven afectados por dicha luz y cuales no. Existen dos formas de realizarlo. La primera es mediante objetos Bound (BoundingSphere, BoundingBox...) o BoundingLeaf. La segunda forma es mediante el alcance de la fuente de luz. Este segundo mecanismo simplifica bastante el tema de control de influencia de un emisor de luz. El alcance se define a través de un nodo Group que establece la lista de objetos que están bajo la influencia de la luz. Para ampliar más se aconseja acudir al capítulo 6 de (J. Bouvier, 1999). 13.3.3.4.3 Clase Material La inclusión de una fuente de luz no significa que los objetos vayan a presentar una apariencia modificada por dicha fuente de luz. Para que esto suceda es necesario definir un objeto Material y enlazarlo con el objeto Appearance del elemento 3D. El objeto Material es del tipo NodeComponent. Este objeto va a permitir definir el color ambiente, el color de difusión, el color especular, así como el color de emisión y el brillo. Los tres primeros colores son los utilizados por el modelo de luz (Lighting Model) para generar los efectos de reflexión anteriormente citados. Cuando para un objeto se define un atributo del tipo Material, este objeto se ve influenciado por la luz (o luces), siempre y cuando entre dentro de los límites de influencia de la fuente luminosa. El lector habrá comprobado que con el objeto Material ya existen tres formas de definir color para un objeto (las otras dos son mediante el objeto Geometry definiendo coordenadas de color o mediante el objeto ColoringAttributes). Quien finalmente defina el color depende de un conjunto de reglas de generación de color preestablecidas. Las siguiente tablas muestran el resultado de dichas reglas. 46
Geometry NO SI NO SI
ColoringAttributes NO NO SI SI
Resultado Material Geometry Material Geometry
Tabla 2 - Reglas de generación de color en presencia de un objeto Material
La Tabla 13. 2 muestra desde donde se tomará el color cuando un objeto de tipo Material se incluya dentro del objeto Appearance del elemento visual (es decir cuando esté influido por la luz). Se puede comprobar como prevalece el color definido por el objeto Geometry, y en su ausencia el color definir por el objeto Material. En ausencia de un objeto Material (el objeto no se verá afectado por la luz) el color se toma siguiendo las siguientes reglas: Geometry NO SI NO SI
ColoringAttributes NO NO SI SI
Resultado En blanco Geometry Coloring Attributes Geometry
Tabla 3 - Reglas de generación de color en ausencia de un objeto Material
13.3.3.4.4 Influencia de las fuentes de luz Un aspecto comentado hasta ahora es el término de límites de influencia. Este concepto ya se introdujo al principio de este apartado. La influencia de una luz va a determinar que objetos se ven afectados por dicha luz y cuales no. Existen dos formas de realizarlo. La primera es mediante objetos Bound o BoundingLeaf. La segunda forma es mediante el alcance o scope de la fuente de luz. Este segundo mecanismo simplifica bastante el tema de control de influencia de un emisor de luz. El alcance se define a través de un nodo Group que establece la lista de objetos que están bajo la influencia de la luz. Para ampliar más se aconseja acudir al capítulo 6 de (J. Bouvier, 1999). En el ejemplo light/LightScopeApp.java se implementa el concepto de alcance de una fuente de luz.
13.3.3.5 Texturas La utilización de texturas es uno de los mecanismos más importantes que permiten dar realismo a una escena 3D. En mucho casos, es la única forma de que un objeto 3D muestre un aspecto real. Algunos objetos que no se representan bien con polígonos planos no texturados son la madera, los ladrillos, el cemento, una alfombra… Por lo tanto se necesita una técnica como el texturado, también llamado mapeo de textura, que añada riqueza visual a una superficie sin la adición de detalles geométricos
47
finos. La riqueza visual la proporciona una imagen, también llamada textura, que da el aspecto del detalle superficial para el objeto visual. La imagen se mapeada dentro de la geometría del objeto visual en el momento de la renderización. De ahí el término mapeo de textura. Al igual que sucedía con las luces la inclusión de texturas es un proceso que requiere el uso de un gran número de clases, de las cuales más adelante se explicarán las más importantes. Pasos a seguir para proporcionar texturado a nuestro objeto: ¾ Preparar las imágenes de texturas: este paso se realiza externamente a los programas de Java 3D y lo que se pretende conseguir es que la imagen que dará la textura a nuestro objeto tenga unas dimensiones aceptables y que el formato del fichero que la almacena pueda ser leído por Java 3D. Una restricción que impone Java 3D es que las imágenes tienen que tener un tamaño potencia matemática de dos en todas las dimensiones porque sino dará una excepción en tiempo de ejecución. Los formatos estándares que carga son JPEG y GIF, aunque la clase TextureLoader también carga otras texturas. ¾ Cargar la textura: consiste en conseguir la imagen preparada en un objeto imagen. Se puede hacer a través de un fichero o de una URL usando un mismo proceso que puede implicar un gran número de líneas de código o por el contrario unas pocas si se usa el objeto TexturaLoader. Si nos fijamos en el siguiente código podemos ver como se usa el objeto TextureLoader para cargar el fichero imagen.gif. TextureLoader loader = new TextureLoader("imagen.gif", this); ImageComponent2D image = loader.getImage();
Las imágenes se cargan de forma asíncrona lo que es muy útil cuando la carga se realiza a través de una URL. Para facilitar el manejo de cargas asíncronas de imágenes, los componentes de AWT están capacitados para ser observadores de imagen, que es observar el proceso de la carga de la imagen. A un observador de imagen se le puede preguntar por los detalles de la carga de la imagen. Con el fin escribir programas Java 3D todo lo que necesitamos saber es que cualquier componente del AWT puede servir como un observador de imagen. Puesto que applet es una extensión del componente Panel del AWT, el objeto applet de un programa de Java 3D puede ser el observador de imagen para el objeto TextureLoader. ¾ Crear el manojo de Appearance: una vez que se tiene cargada la imagen parar poderla utilizar como una textura en un objeto visual se debe asignar como la
48
textura de un objeto Texture. Las siguientes líneas de código se situarán a inmediatamente después que las del paso anterior: Texture2D texture = new Texture2D(); texture.setImage(0, image); Appearance appear = new Appearance(); appear.setTexture(texture);
La imagen entonces se asigna al objeto Texture2D y luego el objeto Texture2D se agrega al objeto Appearance. En este ejemplo no se ha utilizado pero llegados a este punto se suele hacer uso del objeto TextureAttributes que por su gran importancia se explicará más adelante. ¾ Especificar las coordenadas: para finalizar hace falta la colocación de la textura en la geometría a través de la especificación de las coordenadas de textura. Las especificaciones se hacen por cada vértice de geometría. Cada píxel de una textura se llama un texel. Con la especificación de algunos puntos de la imagen que se aplicarán a los vértices de la geometría, la imagen será rotada, estirada, aplastada, y/o duplicada para hacer que quepa en la especificación. Para esto se hace uno del objeto GeometryArray. Una vez completados estos sencillos pasos ya se puede añadir el objeto a un escenario gráfico. 13.3.3.5.1 Clases esenciales de texturado En primer lugar, están los cargadores de texturas. Las clases TextureLoader y NewTextureLoader permiten cargar, a partir de un fichero gráfico externo, una textura para utilizarla dentro de una escena. Ambas clases proporcionan un objeto ImageComponent2D que funciona como un contenedor de la imagen. Esta imagen aún no puede ser utilizada tal y como vimos en el apartado anterior. Una segunda clase que interviene en este proceso es la clase GeometryArray que podía especificar que las coordenadas se referían a aspectos relativos a la textura que se iba a aplicar al objeto visual (mediante los métodos adecuados de la clase GeometryArray o a través de los flags TEXTURE_COORDINATE_2 y TEXTURE_COORDINATE_3). Otro grupo de clases son las derivadas de la clase NodeComponent. Entre estas clases están: ¾ La clase Texture y sus derivadas Texture2D y Texture3D. Estas clases van a permitir tanto importar la imagen del componente ImageComponent2D como configurar ciertos aspectos de cómo se aplicará la textura. Un objeto del tipo Texture se incorpora a la escena enlazándolo con el objeto Appearance relacionado con el objeto Shape3D al que se desea aplicar la textura.
49
¾ La clase TextureAttributes, que permite configurar ciertos aspectos que condicionan la forma en la cual se aplicará la textura. Junto con la clase Texture permite configurar las características más importantes. ¾ La clase TextCoordGeneration que proporciona al programador una forma más sencilla de generar las coordenadas de la textura, que de otra forma se debería incluir “a mano” a través del objeto GeometryArray. Existen más clases que ayudan a la gestión de texturas pero no son objeto de explicación en este documento. A continuación, se describirán con un poco más de detalle las clases Texture y TextureAttributes. Para completar estas clases y para saber más sobre el resto de clases acudir a (J. Bouvier, 1999) y (Sun Microsystems, 1999). Clase Texture Sobre esta clase destacar, principalmente, el hecho de que es la que permite incluir la textura en sí. La clase Texture2D permite incluir texturas en dos dimensiones y la clase Texture3D, como su propio nombre indica, texturas en tres dimensiones. Un aspecto que permite definir la clase Texture es el conocido como Boundary Mode. Es decir, la forma en la cual la textura se aplicará sobre la superficie en caso de que el tamaño de dicha textura no cubra toda la superficie. Para realizar este proceso, existen dos opciones. La primera es la conocida como distribución en mosaico o wrap que se basa en utilizar la textura varias veces para cubrir toda la superficie. La segunda utiliza un color, que también se puede definir, para rellenar los huecos. Si este no se especifica se utiliza el color del límite de la textura para rellenar el espacio. Esta técnica recibe el nombre de clamp. Clase TextureAttributes Esta clase deriva de la clase NodeComponent y sirve de medio para definir características de cómo se aplicará la textura. Puede convivir con el objeto Texture dentro del mismo objeto Appearance. Entre los aspectos que permite definir dicha clase están: ¾ El modelo en el que la textura influirá en el aspecto final del píxel. Como ya se ha visto en el apartado de luces, el aspecto externo de un píxel depende de los atributos de color de distintos objeto y de la influencia de las luces. Este color es el que primero se calcula y luego se completa con el definido por la textura. Existen cuatro formas de definir cómo se combinan textura y color: o BLEND: el color de la textura se mezcla con el color del material arbitrariamente con un color de mezcla. La transparencia que resulta es la combinación de la transparencia de la textura y del material. 50
o DECAL: el color de la textura se aplica como etiqueta encima del color de la no-textura. La transparencia de la textura determina la cantidad de color material a utilizar. La transparencia del píxel se deja sin cambios. Esto es totalmente igual que aplicar una etiqueta a un objeto del mundo real. o MODULATE: el color de la textura se combina con el color de la no-textura. La transparencia que resulta es la combinación de la transparencia de la textura y del material. Puesto que el color que resulta depende de la no-textura y de los colores de la textura, este modo es útil en la aplicación de la misma textura a una gran variedad de objetos visuales sin hacer que todos parezcan iguales. Este modo se utiliza a menudo en escenas de iluminación. o REPLACE: la textura proporciona el color y la transparencia para el píxel, no haciendo caso del resto de los colores excepto del color specular (si se permite la iluminación). Éste es el modo de textura por defecto incluso cuando no hay componente TextureAttributes en el manojo de apariencia.
Figura 18 - Combinación de textura y color
Java 3D por defecto siempre realizar una corrección de la textura en función del punto de vista desde el que se observe el objeto. De esta forma se asegura que la textura siempre se muestre de forma correcta. A través de la clase TextureAttributes se puede definir el grado de corrección que se pretende conseguir mediante dos valores: FASTEST y NICEST, que obviamente premian la velocidad y la calidad de la corrección, respectivamente.
51
13.3.4 Movimiento en Java 3D En el apartado Formas geométricas se ha centrado la atención en la creación de contenidos dejando a un lado aspectos de transformación de la escena como rotaciones, translaciones... Este tipo de aspectos se abordan en esta sección. En primer lugar, se describen ciertos conceptos esenciales para la comprensión de la forma en la que Java 3D aborda el tema del movimiento dentro de un universo virtual. A continuación, se introducen los mecanismos más avanzados presentes en el API para realizar animaciones así como para controlar la interacción con el usuario.
13.3.4.1 Conceptos básicos En este punto, se describen los fundamentos básicos que proporciona el API de Java 3D para transformar la situación inicial de las figuras en una escena. 13.3.4.1.1 Traslaciones y rotaciones en Java 3D Con anterioridad se introdujeron las clases TransformGroup y Transform3D. Estas dos clases son el germen para realizar modificaciones sobre la posición y orientación por defecto de una figura 3D. La clase Transform3D proporciona métodos que permiten realizar translaciones de una figura desde un punto del espacio a otro, rotaciones respecto a un eje determinado y con un ángulo dado... En una palabra, va a encapsular toda la lógica de procesamiento de matrices implicada en el proceso de transformación gráfica. Un objeto Transform3D realiza una sola operación de transformación básica. Como consecuencia de esa transformación, la figura afectada dentro del grafo de escena mostrará una nueva posición o una nueva orientación o ambas cosas. Si se desea aplicar nuevas transformaciones a partir de dicha situación, no es necesario más que crear otro objeto del tipo Transform3D, determinar la transformación a realizar y combinar las dos instancias de los objetos Transform3D. Como consecuencia de esta combinación, las matrices de transformación que encapsulan las instancias de los objetos Transform3D implicados se multiplican dando como resultado la transformación final. Una vez creada la transformación, ésta se incluye en el grafo de escena añadiendo la instancia de la clase Transform3D que contiene el resultado de la multiplicación de todas las matrices a una instancia de la clase TransformGroup. Para que la transformación tenga efecto, la figura 3D objeto de la transformación se debe añadir como hija de la instancia de la clase TransformGroup para la que se ha definido la transformación.
52
13.3.4.1.2 Concepto de capacidad El proceso descrito en el punto anterior, se realiza de forma previa a la compilación11 de la rama generada y la visualización de la escena. Es decir, se hace en tiempo de diseño del universo. Sin embargo, una vez creada la escena, ésta es totalmente estática. Para evitar que tras la compilación de una rama, los valores definidos para cada figura queden inmutables, se define el concepto de bit de capacidad (capability bit). A través de estos bits no sólo se puede establecer que una figura pueda ser objeto de transformaciones una vez incluida en el grafo de escena, sino que además decidir que sólo sea susceptible de ciertos tipos de transformaciones. Además, al definirse el concepto de capacidad a nivel de la clase SceneGraphObject, cada elemento 3D tendrá sus propias capacidades. Por supuesto, la activación de los bits de capacidad de un elemento del grafo de escena, se debe realizar de forma previa a la compilación y ejecución de la rama del árbol implicada. La clase SceneGraphObject proporciona métodos adecuados que permiten activar y desactivar estos bits. Las diferentes clases que componen Java 3D se caracterizan por un conjunto de bits de capacidad diferentes. Para conocer dichos flags acudir a (Sun Microsystems,1999). 13.3.4.1.3 Comportamientos El comportamiento se articula en torno a una clase denominada Behavior. Esta clase se encarga de modificar los objetos de la escena 3D ante distintos estímulos, y en particular estímulos procedentes de la interacción del usuario. Las modificaciones que se pueden realizar a través de la clase Behavior y sus descendientes está únicamente limitada por las capacidades de cada uno de los objetos del grafo de escena. El objetivo final de una instancia de la clase Behavior es la modificación de un determinado objeto. Este objeto se conoce como objeto de cambio. Por supuesto, la instancia encargada de la gestión del comportamiento debe tener una referencia al objeto susceptible de ser cambiado. Esta referencia se debe incluir en el momento de construcción del grafo de escena. De hecho, es uno de los parámetros del constructor. Funcionamiento El comportamiento posee un método específico que lo inicializa: initialization(). Este método es responsable de cargar el disparador (trigger) encargado de responder al evento y
11
El concepto de compilación se introdujo en el apartado Modos de renderización
53
la condición para que dicho evento se dispare12. El disparador es un objeto de la clase WakeupCondition o una combinación de objetos de dicha clase. Una vez que el comportamiento está activado y dispuesto para recibir eventos, dicho comportamiento será capaz de capturar el evento producido mediante el método processStimulus(). Este método es el lugar apropiado para incluir aquellas acciones a ejecutar cuando se recibe el evento. Otra tarea que debe realizar este método es la reactivación del evento. Es decir, debe volver a habilitar el disparador cuando se haya terminado de procesar el evento, para así poder recibir nuevos eventos. Si esto no se realiza, el comportamiento sólo respondería al evento que se quiere controlar una sola vez. Uso de comportamientos Conocido el funcionamiento de un elemento de comportamiento, el siguiente paso es analizar cómo se utiliza. El primer paso es configurar de forma adecuada el elemento (o elementos) que va a ser objeto de modificación por parte del comportamiento. Además de la creación de este elemento, será necesario establecer las capacidades adecuadas que permitan actuar sobre él una vez que el grafo de escena esté construido. El siguiente paso es crear una instancia del comportamiento que se desea exhibir prestando atención en el hecho de que el comportamiento debe tener la referencia al objeto que desea modificar. El tercer paso es determinar el alcance de acción del comportamiento. Se utilizará un objeto BoundingSphere, BoundingBox o BoundingPolytope para determinar dichos límites. Para Java 3D, un comportamiento sólo está activo si sus límites intersecan con el volumen de activación determinado para el objeto ViewPlatform13, y sólo sí el comportamiento está activo puede recibir eventos. Por lo tanto, hay que prestar atención a la hora de determinar los límites de un comportamiento para asegurar que reciba los eventos cuando se desea. El último paso, sería añadir el objeto que controla el comportamiento a la rama del grafo. En la siguiente figura se puede ver el resultado final de las conexiones entre los distintos elementos comentados de dos formas diferentes.
12
Es común que se desea controlar sólo el evento de clic del ratón ignorando el evento de movimiento del ratón. Sin embargo, ambos son eventos de ratón. La condición del evento permite la diferenciación de eventos relacionados semánticamente.
13
Esta clase se describe en la sección ViewPlatform: Un lugar en el mundo virtual.
54
Figura 19 - Grafo de escena que incorpora un comportamiento
En estos grafos, el elemento B (Behavior) es el comportamiento y el elemento TG (TransformGroup) es el objeto susceptible de ser transformado. Si la transformación fuese realizar una rotación, el resultado sería que toda la rama por debajo de TG se vería rotada, en este caso el cubo de color. La diferencia entre las dos formas de conexión está en que, en el primer caso, el objeto que se rota se desplaza pero el comportamiento no se desplaza con él. En el segundo caso, como el comportamiento depende del objeto transformado, también se verá afectado por la rotación y se desplazará con el objeto. A primera vista, los dos enfoques son idénticos, pero no es así. Antes se ha comentado que, para que un objeto comportamiento esté activo es necesario que sus límites intersecten con el volumen de la vista (objeto ViewPlatform). Imagínese que el objeto ViewPlatform se cambia, de tal forma que el comportamiento no interseca con el volumen de la vista, pero el cubo sigue visible. El comportamiento no está activo y el usuario que sí puede ver el cubo no puede interactuar con él. En el segundo caso, esto nunca sucedería, ya que mientras la figura esté visible, el comportamiento estará activo. Sin embargo, bajo el enfoque de la derecha, el cubo nunca podrá abandonar la vista en su proceso de rotación, mientras que con el enfoque de la derecha la figura seguiría siendo rotada aunque estuviera fuera de la vista del usuario ya que el comportamiento sí estaría dentro del volumen de la vista. Condiciones de inicio Como ya se ha comentado antes, es necesario configurar un comportamiento para que responda a un determinado evento. Para ello se utilizan las condiciones de inicio implementadas a través de la clase WakeupCondition y derivadas. Se pueden establecer dos grupos. El primero lo forman la clase WakeupCriterion y sus derivadas. El segundo, el resto de clases derivadas de WakeupCondition.
55
Esta distinción se realiza porque el primer grupo sirve como mecanismo para agrupar condiciones de arranque del segundo grupo. Las verdaderas condiciones de inicio son las del segundo grupo. No se va a entrar a detallar cada uno de los criterios de inicio existentes. Para conocer detalles sobre ellos acudir a (J. Bouvier, 1999) y a (Sun Microsystems, 1999).
13.3.4.2 Interacción con el usuario Una vez conocidos los primeros pasos para incorporar transformaciones en una escena 3D, se va a analizar cómo realizar dichas transformaciones ante eventos generados por la interacción del usuario con el universo creado. De todas las clases que descienden de la clase Behavior, las implicadas en la interacción con el usuario son las que se muestran a continuación.
Figura 20 - Clases de comportamiento implicadas en la interacción con el usuario
56
13.3.4.2.1 Interacción a través del teclado El primer elemento disponible para que el usuario interaccione con un programa es el teclado. Mediante el control de teclas, el usuario va a poder modificar la escena. En este capítulo, se muestra como se puede utilizar los comportamientos vistos con anterioridad para gestionar este tipo de interacción con el usuario. El control del teclado en Java 3D se realiza a través de las clases KeyNavigatorBehavior y KeyNavigator. La primera clase es la que realmente utiliza el programador para controlar la pulsación de teclas. La segunda clase queda oculta al programado y no es necesario que éste sepa de su existencia para poder manejar el teclado. Esta última clase es la que se encarga de la lógica de la función processStimulus(). La respuesta de esta función a los eventos del teclado está predefinida para ciertas teclas que son comúnmente utilizadas. En la siguiente tabla se muestran los comportamientos por defecto.
Tabla 4 - Tablas de movimientos predefinidos en Java 3D
La clase que se debe instanciar para controlar los eventos del teclado es la clase KeyNavigatorBehavior, que como tal comportamiento deberá incorporar una referencia al objeto que se desea transformar. Si se desea, el usuario puede crear su propia clase comportamiento que controle el teclado y así controlar la pulsación de teclas que se consideren oportunas. Un ejemplo de uso de las teclas de navegación del teclado se puede ver en interaction/KeyNavigatorApp.java.
57
13.3.4.2.2 Gestión del ratón Otro dispositivo utilizado por el usuario para interaccionar con un programa es el ratón. Java 3D proporciona los comportamientos necesarios para controlar los distintos eventos que puede generar el ratón. Entre estos eventos está la pulsación de cada uno de los botones. El evento no se dispara por el hecho de pulsar un botón sino por pulsar y desplazar el ratón sin soltar el botón pulsado. Por defecto, cada uno de los botones del ratón tiene un efecto preestablecido que es controlador por una clase diferente en cada caso: La pulsación del botón izquierdo acompañada de movimiento provoca que el objeto visual rote. Este evento lo controla la clase comportamiento MouseRotate. El desplazamiento del ratón manteniendo pulsado el botón derecho provoca que la figura se desplace siguiendo una trayectoria paralela al plano de imagen. Este evento lo controla la clase MouseTranslate, que por supuesto es otro comportamiento. Por último, la pulsación del tercer botón del ratón con desplazamiento de este provoca una alteración del zoom de la imagen, o lo que es lo mismo, desplaza la imagen en un plano ortogonal al plano de imagen. Este evento lo controla la clase MouseZoom. Los tres comportamientos se pueden incorporar de forma simultánea a un programa y para controlar el mismo objeto visual, como no podría ser de otra forma. Estas tres clases descienden en la jerarquía de la clase abstracta MouseBehavior que implementa la interfaz MouseCallback. La clase abstracta es el punto de partida idóneo para crear, por parte del programador, un comportamiento que maneje el ratón. De hecho, la mayor parte de métodos de esta clase se deben sobrescribir. Por otro lado, la interfaz proporciona un método, transformChanged() que es invocado cada vez que el objeto susceptible del campo es transformado. En el apartado de recursos pueden consultarse varios ejemplos sobre interacción con el ratón. Entre ellos se recomienda interaction/MouseBehaviorApp.java. 13.3.4.2.3 Discriminación de objetos Mientras no se especifique lo contrario, las interacciones a través del teclado o del ratón afectan a todo el universo, desplazando toda la escena. Para determinar un objeto concreto como el objetivo del evento se debe utilizar los que se denomina picking. Como parece lógico, este mecanismo se implementa como un comportamiento que responde ante eventos de ratón (¿cómo si no se va a acceder a un elemento concreto dentro de una escena 3D?).
58
El funcionamiento es el siguiente: En primer lugar se determina el objeto visual que se desea manipular, con el ratón. En el momento que se pulse un botón del ratón sobre dicho objeto y se desplace el ratón se dispara el evento. Para determinar que objeto hay que manipular, el sistema genera un rayo denominado pick ray que se proyecta dentro del universo virtual. Este rayo interfecta con el objeto más cercano al usuario. Este objeto será el que se vea afectado por la interacción. Es posible que la proyección del rayo interseque con más de un objeto, en este caso existen métodos para ir seleccionando cada uno de dichos objetos (objeto PickObject).
Figura 21 - Discriminación de un objeto visual mediante el mecanismo pick ray
Un buen ejemplo de discriminación de un objeto dentro de una escena se puede observar en interaction/MousePickApp.java. La interacción con una figura concreta es una operación muy costosa en tiempos de computación. El primer lugar, ciertos tipos de interacciones (rotaciones, translaciones...) no afectan al objeto visual en sí sino a alguno de los nodos TransformGroup por encima en el grafo de escena. Por otro lado, si el objeto está formado por numerosos elementos geométricos (por ejemplo un cubo que este formado por cuatro caras individuales), cada uno de estos objetos deber ser objeto de la interacción. No es objeto de este documento entrar en cómo optimizar el coste de este tipo de interacciones. Para conocer más acudir a (J. Bouvier, 1999). Siguiendo la tónica de trabajo de Java 3D se proporcionan clases que permiten manejar la interacción sobre un objeto concreto y se proporcionan un conjunto de clases útiles para crear nuevos comportamientos por parte del programador. Todas ellas se encuentran en el paquete com.sun.j3d.utils.behavior.picking.
59
Las clases predefinidas en el API son PickRotateBehavior, PickTranslateBehavior y PickZoomBehavior. Para crear una instancia de cualquiera de estas tres clases es necesario establecer tres parámetros: 1. El primero es el nodo dentro del grafo de escena por debajo del cual se va a controlar los eventos. 2. El segundo parámetro es el marco en el cual se mueve el ratón, es decir el objeto Canvas3D creado para mostrar la escena. 3. El último parámetro indica los límites de acción del comportamiento. Cada clase anterior controla los eventos del ratón correspondientes a pulsar el botón izquierdo, derecho y central, respectivamente (junto con el desplazamiento de este dispositivo). La construcción de comportamientos propios para controlar este tipo de eventos no es objeto de este documento. Para saber más sobre las clases proporcionadas por Java 3D que permiten crear comportamientos propios para el control de este tipo de interacciones, acudir a (J. Bouvier, 1999).
13.3.4.3 Animación en Java 3D En el apartado anterior se ha introducido la forma de incluir movimiento en una escena 3D mediante el control de la interacción del usuario. En este apartado, se analiza cómo incluir animaciones. Esto supone movimiento sin ningún tipo de interacción por parte del espectador. De la jerarquía de la clase Behavior, las clases involucradas en la generación de animaciones son las que se muestran en la siguiente figura.
Figura 22 - Jerarquía de clases Behavior involucradas en la animación
Además de estas clases, existen otras clases adicionales que contribuyen de alguna forma a la generación de escenas animadas. La forma más natural de crear una animación es realizando transformaciones sobre la escena de forma continua en el tiempo. Para ello, además de los comportamientos vistos 60
hasta ahora, que permiten incluir modificaciones, es necesaria una fuente de reloj que vaya marcando el tiempo. Java 3D proporciona los dos elementos. Los comportamientos implicados se conocen como interpoladores (Interpolator) y el reloj lo implementa la clase Alpha. La característica principal de los objetos Interpolator es que son capaces de actual en función de un objeto Alpha. Aunque los interpoladores no son la única forma de crear animación basada en el tiempo, sí es la forma más rápida y sencilla. A continuación, se analizan cada uno de los elementos implicados. Alpha Este objeto genera valores entre 0.0 y 1.0 que varían con el tiempo como muestra la siguiente figura.
Figura 23 - Pulso de tiempo generado por un objeto Alpha
Como se puede ver, el pulso generado por el objeto Alpha tiene cuatro fases: fase de crecimiento, fase alta, fase de decrecimiento y fase nula. Cada una de estas fases corresponde con un valor entero que se puede configurar en la creación del objeto. El número de pulsos que genera el objeto Alpha es otro de los parámetros que se pueden configurar. Puede variar entre un determinado tiempo máximo e infinito. Este tiempo no aparece en la figura anterior y se conoce como timeCount. El tiempo inicial de un objeto Alpha se obtiene del tiempo de inicio de la aplicación, con lo que todos están sincronizados aunque se hayan creado en diferentes momentos.
61
La Figura 13.23 muestra la forma habitual de los pulsos generados por el objeto Alpha, pero no son las únicas formas posibles. En la siguiente figura se pueden observar otras formas de onda que se pueden utilizar.
Figura 24 - Formas alternativas de onda generadas por un objeto Alpha
La forma del pulso condiciona los instantes en los que se dispara el evento y por lo tanto, el momento en el cual el comportamiento entra en juego. Otras características importantes que se pueden configurar en un objeto Alpha son el parámetro increasingAlphaDuration y el parámetro increasingAlphaRampDuration. En la siguiente figura se puede observar cómo afecta cada uno al pulso.
Figura 25 - Suavizado del pulso de tiempo generado por un objeto Alpha
Los efectos que se consiguen al suavizar la curva son relativos a la aceleración con la cual se dispara el comportamiento que modifica el objeto. En la siguiente figura, se muestra este efecto en el movimiento de tres coches.
62
Figura 26 - Resultados de suavizar un pulso de tiempo de un objeto Alpha
Interpoladores Una vez analizada la clase que permite generar eventos de tiempo, el siguiente paso es centrarse en los interpoladores. En la siguiente figura, se muestra la jerarquía de clases para los interpoladores.
Figura 27 - Jerarquía de clases de los interpoladores
A continuación, se van a describir, de forma breve, cada uno de los interpoladores de la figura. En el ejemplo animation/InterpolatorApp.java se hace uso de alguno de los interpoladores que se van a describir a continuación. ColorInterpolator Este interpolador altera el color de una determinada figura. Para ello, esta clase mantiene una referencia a atributo de la figura visual que define el color (Material). Puesto que este tipo de nodos (en general los nodos del tipo NodeComponent) se pueden compartir entre figuras, el interpolador podría alterar el color de un conjunto de objetos visuales de forma sencilla y rápida.
63
El valor generado por el objeto Alpha se interpola entre dos vectores que definen un rango de color, para generar el color resultado. PathInterpolator Tanto la clase ColorInterpolator como los siguientes interpoladores que se van a explicar a continuación, utilizan el mecanismo de interpolación entre dos valores como mecanismo de trabajo. En cambio, las clases derivadas de la clase PathInterpolator pueden almacenar más de dos valores para realizar la interpolación. Estas clases mantienen una referencia a un objeto TransformGroup sobre el cual van a realizar cambios de posición, orientación y escala (y por lo tanto sobre sus descendientes). El conjunto de puntos que almacena esta clase se conocen como knots. Cada vez se utilizan dos de estos puntos para realizar la interpolación. Cuáles se elijan depende del valor del objeto Alpha. El valor de estos knots varía entre 0.0 y 1.0, que corresponde con los valores entre los que varía el valor generado por el objeto Alpha. Además, el primer punto del conjunto de knots debe tener el valor 0.0 y el último el valor 1.0. El resto se definen en orden creciente. Cada knot tiene asociado un valor que permite determinar cuál se activa dependiendo del valor del objeto Alpha. En la siguiente figura se puede observar esta correspondencia y cómo se selecciona un knot para un valor determinado del objeto Alpha.
Figura 28 - Pares knot/valor y criterio de seleccion de un knot
Por otro lado, se puede ver cómo cada knot tiene además un valor asociado que representa la información válida para realizar la animación. En el caso de la figura anterior, esta información es un vector de puntos. La clase PathInterpolator es la superclase de un conjunto de clases, cada una de las cuales encargada de un comportamiento diferente. Además, existen una serie de clases de utilidad relacionadas con estos interpoladores.
64
Entre las clases derivadas está la clase PositionInterpolator que define pares knot/posición para alterar la posición; la clase RotationInterpolator que actúa sobre la orientación; la clase RotPosPathInterpolator que permite variar la posición y la orientación y, por último, la clase RotPosScalePathInterpolator que permite variar tanto posición como orientación como escala. En el paquete de utilidad está la clase TCBPathSplineInterpolator (con una clase derivada) que funciona de forma similar a la clase PathInterpolator pero utiliza interpolación por esplines con lo cual permite obtener animaciones más suaves. PositionInterpolator Este interpolador permite variar la posición de un objeto visual a lo largo de un determinado eje de coordenadas. Mantiene una referencia a un objeto TransformGroup que va a desplazar entre una posición inicial y otra posición final (ambas especificadas mediante número reales). El objeto Alpha genera un valor que se interpola dentro del rango establecido siguiendo una interpolación lineal. El valor interpolado se utiliza para generar una translación sobre el objeto TransformGroup (la translación se realiza mediante un objeto Transform3D). RotationInterpolator Permite variar la orientación de un objeto visual sobre un eje. Al igual que en el caso anterior, mantiene una referencia a un objeto TransformGroup. En este caso, el valor generado por el objeto Alpha se interpola entre dos valores de ángulos (siguiendo una interpolación lineal). De nuevo, para realizar la transformación se utiliza un objeto Transform3D que establece, además, sobre que eje realizar el giro. ScaleInterpolator Este interpolador va a permitir modificar la posición de un objeto visual, acercándolo o alejándolo del espectador. En este caso, se interpola entre dos valores que establecen un rango de escala para el objeto TransformGroup objetivo de la transformación. La forma de aplicar la transformación es como en los casos anteriores. SwitchValueInterpolator Este interpolador no interpola entre un par de valores como en los casos anteriores, sino entre un conjunto de elementos denominados Switch. La clase Switch, básicamente, actúa como un contenedor de elementos (de hecho deriva de la clase Group). El valor generado por el objeto Alpha se interpola entre el valor 0 y el número total de elementos contenidos en el objeto Switch. Esto permite elegir uno de
65
los hijos, que será el que se muestre en la escena. A modo de ejemplo, mediante el uso de ese interpolador se puede mostrar una secuencia de imágenes cualesquiera. La potencia de la clase Switch está en que permite definir en cada momento qué objetos, de entre los que mantiene, se van a visualizar (todos, sólo los que cumplan un patrón o ninguno). TransparencyInterpolator Este interpolador mantiene una referencia a un objeto del tipo TransparencyAttribute, por lo cual podrá cambiar la transparencia asignada al objeto visual, y si el nodo TransparencyAttribute es compartido por más de un objeto visual, podrá cambiar la transparencia de todos ellos. En este caso, el valor del objeto Alpha se interpola entre dos valores de transparencia. Billboard Este concepto se utiliza en el mundo del diseño 3D para identificar la técnica que consiste en rotar, de forma automática, elementos en un plano de tal forma que siempre se muestran de frente al usuario. El objetivo original de esta técnica es la utilización de una estructura plana para simular una estructura tridimensional más compleja, con mucho menos coste de procesamiento. El API de Java 3D proporciona la clase Billboard que hereda de forma directa de la clase Behavior. La forma de usar esta clase es similar al uso de los interpoladores con la salvedad de que no existe relación con un objeto Alpha. En este caso, la animación se basa en la posición relativa del objeto Billboard dentro del mundo virtual. Cualquier alteración del punto de vista de la escena provoca que se desencadene la acción de este tipo de comportamiento de forma que el objeto controlado siempre se muestra de frente al usuario. Un ejemplo sobre este animation/BillboardApp.java.
tipo
de
comportamiento
se
puede
ver
en
LOD Las siglas LOD (Level Of Detail) identifican la técnica que consiste en variar la cantidad de detalle con el cual se dibuja un determinado objeto visual dependiendo de su posición en el universo virtual, concretamente atendiendo a la distancia respecto al espectador. Así, a medida que un objeto se aleja, el nivel de detalle con el que es necesario representarlo es menor con lo que se reduce el esfuerzo de visualización del objeto. La clase DistanceLOD implementa esta funcionalidad. Otro parámetro que posibilita alterar el nivel de detalle con el que se muestra una figura es la velocidad de visualización.
66
La forma de trabajo consiste en utilizar un objeto Switch (ya se vio este objeto en el apartado SwitchValueInterpolator) con el conjunto de objetos que se mostrarán dependiendo de la distancia al espectador. El primer elemento visual especificado es el de mayor nivel de detalle. El último, el de meno nivel de detalle. El objeto LOD puede trabajar con varios objetos Switch de forma paralela, con lo que podrá controlar la visualización de distintos objetos.
67
13.4 MODELO DE VISUALIZACIÓN Java 3D introduce un nuevo modelo de vista que toma el espíritu típico de Java de “escribe una vez y ejecútalo en cualquier lugar” y que lo generaliza para incluir dispositivos de imagen y periféricos de entrada con seis grados de libertad como los head trackers. Este espíritu del nuevo modelo implica que una aplicación o un applet escrito utilizando el modelo de vista de Java 3D puede generar imágenes en un amplio abanico de dispositivos, que van desde las pantallas de los ordenadores convencionales hasta dispositivos “montados en la cabeza” (como por ejemplo gafas de realidad virtual). Todo ello sin tener que modificar el grafo de escena. Este nuevo modelo también logra que la misma aplicación, y una vez más sin realizar ninguna modificación, puede generar vistas estereoscópicas y puede aprovecharse de un head tracker para controlar la vista generada. Para obtener esta gran versatilidad, Java 3D realiza una clara separación entre el mundo virtual y el físico. Este modelo distingue entre cómo una aplicación coloca, orienta y escala un objeto ViewPlatform (un punto de vista) dentro del mundo virtual y cómo el generador de Java 3D construye la vista final desde la orientación y posición de ese mismo punto de vista. La aplicación controla la posición y orientación del ViewPlatform; el generador obtiene qué vista debe generar utilizando dicha posición y orientación, una descripción del entorno físico del usuario y la posición y orientación del propio usuario dentro de dicho entorno físico. Tanto los modelos basados en cámara, como los basados en Java 3D permiten a los programadores especificar la forma del fustrum de la vista y, bajo el control del programa, colocarlo, moverlo, orientarlo..., dentro del entorno virtual. Sin embargo, lo que varía entre unos modelos y otros es cómo lo hacen. Los modelos basados en Java 3D permiten configurar el fustrum de acuerdo con 6 grados de libertad (que se corresponden con los dispositivos de reastreo o tracking), de tal forma que puede modificar dicho fustrum para generar imágenes adaptadas al punto de vista concreto del usuario final.
13.4.1 Justificación Los modelos de vista basados en cámara propios de APIs de bajo nivel, proporcionan a los programadores el control de todos los parámetros de la generación de imágenes. Esto resulta muy apropiado cuando se están desarrollando aplicaciones personalizadas, pero resulta menos adecuado cuando se trata de sistemas que intentan disponer de una mayor aplicabilidad, sistemas como visores o navegadores que cargan y muestran mundos enteros como un solo elemento o sistemas donde el usuario final observa, navega e incluso interactúa con el mundo virtual generado. Los modelos de vista basados en cámara emulan una cámara en el mundo virtual, no a una persona en dicho mundo. Los desarrolladores deben cambiar la posición de la cámara continuamente para emular a un humano en el mundo virtual. El modelo de vista de Java 3D incorpora el head tracker directamente, en caso de que exista, sin ningún tipo de
68
esfuerzo adicional por parte del desarrollador y proporcionando a los usuarios la sensación de encontrarse dentro del mundo virtual. Cuando el modelo de vista de Java 3D opera en un entorno sin head tracker y cuando genera las imágenes en una sola pantalla, actúa de forma muy similar a los tradicionales modelos de vista basados en cámara, pero con la funcionalidad añadida de ser capaz de generar, de forma transparente, vistas estéreo.
13.4.2 Influencia del entorno físico en la vista No se resulta muy adecuado dejar que la aplicación controle todos los parámetros de visualización si el entorno físico determina parte de dichos parámetros. Por ejemplo, en caso de disponer de un dispositivo de salida “montado en la cabeza” (algo como un casco o unas gafas multimedia), es dicho dispositivo el que determina el punto de vista que debe usar la aplicación. Además, diferentes dispositivos tienen diferentes puntos de vista, con lo cual, sería inútil dejar prefijados ciertos parámetros de antemano. Los parámetros de visualización pueden variar mucho dependiendo de los detalles físicos del entorno del usuario. Factores que influyen mucho en dichos parámetros son el tamaño del dispositivo físico, dónde se encuentra situado (en una mesa o en la cabeza del usuario), si el ordenador conoce la posición de la cabeza del usuario en el espacio, la resolución del dispositivo, etc. Para explicar todo esto con mayor claridad vamos a ver un pequeño ejemplo. Supongamos que el usuario se sienta en una alfombra mágica y que la aplicación que esta utilizando hace volar al usuario por el entorno virtual controlando la posición y orientación de la alfombra dentro del mundo virtual. Parece, a primera vista, que la aplicación también tiene que controlar lo que el usuario ve, y lo hace, pero sólo superficialmente. Ahora podremos ver cómo el entorno del usuario final puede afectar de forma significativa cómo una aplicación debe construir las transformaciones de visualización.
13.4.2.1 Sistema montado en la cabeza Supongamos que el usuario ve la alfombra mágica y el mundo virtual a través de un dispositivo montado en su cabeza y que dispone de un head tracker. A medida que la aplicación hace volar la alfombra por el mundo virtual, el usuario puede girarse para mirar a la izquierda o a la derecha o hacia la parte trasera de su alfombra. Debido a la utilización del head tracker, el generador de imágenes dispone de la información suficiente para saber hacia dónde mira el usuario y no necesita dibujar la escena en frente de la alfombra mágica. La vista que el generador de imágenes dibuja en el dispositivo montado en la cabeza del usuario debe adaptarse a lo que el usuario vería si la experiencia ocurriera en el mundo real.
69
13.4.2.2 Sistema montado en una habitación Supongamos ahora un entorno ligeramente diferente. El usuario se sienta en una habitación oscura delante de una gran pantalla de proyección. La aplicación todavía controla el vuelo de la alfombra, sin embargo, la posición y orientación de la cabeza del usuario apenas influye en la imagen dibujada en la pantalla. Si el usuario mira a izquierda o a derecha, sólo ve la habitación oscura. La pantalla no se mueve y, como la pantalla representa, de alguna forma, la ventana frontal de la alfombra, la habitación representa el interior oscuro de la misma. Si se añadieran pantallas a la izquierda y a la derecha, se le proporcionaría al conductor de la alfombra una visión más completa del mundo virtual que rodea a la alfombra. En ese caso, el usuario podría ver la vista a la derecha o la izquierda de la alfombra simplemente girando su cabeza. En el ejemplo usando un dispositivo “montado en la cabeza” , la posición y orientación de la cabeza del usuario afectan significativamente la posición y orientación de la cámara del modelo, pero apenas influye en la matriz de proyección. En el ejemplo con un sistema “montado en la habitación” , la posición y orientación de la cabeza del usuario no influye apenas en la posición y orientación de la cámara, pero sí influye en la matriz de proyección. Desde una perspectiva basada en una cámara, el desarrollador de la aplicación debe construir la posición y orientación de la cámara combinando el componente relativo al mundo virtual (la posición y orientación de la alfombra) y el componente del mundo físico (la posición y orientación de la cabeza del usuario). El modelo de vista de Java 3D incorpora las abstracciones apropiadas para compensar toda esta posible variabilidad de los entornos de usuario.
13.4.3 Separación de físico y virtual El modelo de visualización de Java 3D separa el entorno virtual, donde el programador ha colocado los distintos objetos unos en relación con los otros, del entorno físico, donde el usuario sí existe, ve los dispositivos de salida del ordenador y manipula los de entrada. Java 3D define también una correspondencia fundamental entre el mundo físico del usuario y el mundo virtual de la aplicación gráfica. Esta correspondencia define un espacio común donde una acción llevada a cabo por el usuario afecta a los objetos en el mundo virtual y donde cualquier actividad de los objetos en el mundo virtual afecta la vista del usuario.
13.4.3.1 El mundo virtual El mundo virtual es un espacio común en el que existen los objetos virtuales. El sistema de coordenadas del mundo virtual existe de forma relativa a un Locale de alta resolución (cada objeto Locale define el origen de unas coordenadas del mundo virtual para todos los objetos 70
unidos a dicho Locale). El objeto Locale que contiene al objeto ViewPlatform activo define las coordenadas del mundo virtual utilizadas para generar las imágenes. Java 3D transformará, eventualmente, todas las coordenadas asociadas con los elementos del grafo de escena para incluirlos en el espacio común del mundo virtual.
13.4.3.2 El mundo físico El mundo físico es, simplemente, el mundo real. Es el espacio en el que existe el usuario en el que mueve su cuerpo, su cabeza, sus manos... Es el espacio en el que cualquier rastreador físico define sus coordenadas locales y en el que se describen varios sistemas de coordenadas de calibración. El mundo físico es un espacio, no un sistema de coordenadas común entre diferentes instancias de ejecución de Java 3D. Así, si dos ordenadores diferentes, en dos posiciones físicas distintas en el mundo están ejecutando una aplicación a la vez, Java 3D no dispone ningún mecanismo directo para relacionar los sistemas de coordenadas del mundo físico de cada uno de ellos. Son las características propias de cada entorno las que definen el sistema de coordenadas local de cada mundo físico.
13.4.4 Objetos que definen la vista Java 3D distribuye los parámetros del modelo de visualización en distintos objetos: el objeto View y los objetos componentes asociados con él, el objeto PhysicalBody, el objeto PhysicalEnvironment, el objeto Canvas3D y el objeto Screen3D. A continuación se describe brevemente el papel de cada uno de estos objetos en el sistema: ¾ ViewPlatform. Es un nodo hoja que ubica una vista dentro de un grafo de escena. Sus padres especifican su posición, orientación y escala en el mundo virtual. ¾ Canvas3D. El objeto Canvas3D encapsula todos los parámetros relativos a la ventana en la que se está renderizando. Cuando se une un objeto Canvas3D a un objeto View, Java 3D renderiza la vista especificada en la pantalla. Varios objetos Canvas3D pueden referirse al mismo objeto View. Canvas3D extiende el objeto java.awt.Canvas para incluir información relativa a los objetos 3D como pueden ser el tamaño en píxeles del lienzo, la localización del mismo también en píxeles dentro de un objeto Screen3D y si el lienzo tiene activada o no la opción de estéreo. Como todos los objetos Canvas3D contienen una referencia a un objeto Screen3D, y debido a que los objetos Screen3D definen el tamaño de un píxel en unidades física, Java 3D puede convertir un tamaño en píxeles en un tamaño del mundo real en metros. También puede determinar la posición y orientación del Canvas3D en el mundo real.
71
¾ Screen3D. El objeto Screen3D encapsula todos los parámetros asociados con la pantalla física que contiene el lienzo. Estos parámetros pueden ser la anchura y altura de la pantalla en píxeles, las dimensiones físicas de la pantalla y varios valores de calibración física. Este objeto proporciona la versión 3D del objeto Screen de AWT. Java 3D permite tener activos varios objetos Screen3D de forma simultánea. Por supuesto sólo se pueden utilizar varias pantallas si la configuración de la máquina que se utiliza dispone de varias pantallas de salida. Un objeto Screen3D representa un dispositivo independiente. La configuración más convencional para Java 3D es un ordenador de sobremesa con una sola pantalla. Sin embargo, Java 3D puede aprovechar entornos en los que se necesitan tres o más pantallas. Estos entornos requieren un mayor cuidado en la inicialización y en la calibración. Java 3D debe conocer las posiciones relativas de los objetos Screen3D (de cada uno respecto del resto). ¾ View. El objeto View especifica la información necesaria para renderizar el grafo de escena. El objeto View es el objeto central de Java 3D para coordinar todos los aspectos de visualización. Todos los parámetros de visualización de Java 3D o bien están contenidos directamente dentro del objeto View o bien lo están en objetos accesibles desde un objeto View. Java 3D permite el uso simultáneo de varios objetos View activos, cada uno de los cuales puede renderizar uno o más lienzos. Este objeto coordina todos los aspectos del proceso de renderización. Contiene los parámetros o referencias a los objetos que contienen los parámetros que determinan cómo renderizar las imágenes en las ventanas representadas por sus correspondientes objetos Canvas3D. También contiene el conjunto de lienzos que representan varias ventanas en una misma vista. ¾ PhysicalBody. El objeto PhysicalBody encapsula todos los parámetros asociados con el cuerpo físico como pueden ser la posición de la cabeza, del ojo derecho e izquierdo, los oídos, izquierdo y derecho e incluso la distancia entre ambas pupilas. El objeto PhysicalBody contiene información relativa a las características físicas del cuerpo del usuario. Los parámetros relativos a la cabeza permiten a dichos usuarios especificar las características de su propia cabeza para adaptar las aplicaciones de Java 3D de tal forma que se adapten a su propia geometría. El objeto PhysicalBody define un sistema de coordenadas relativo a la cabeza del espectador, que sirve de punto de referencia para definir los parámetros de su cabeza. Dicho sistema de coordenadas tiene su origen en el plano bilateral de simetría de la cabeza, aproximadamente a mitad de camino entre el ojo izquierdo y el derecho. El origen del sistema de coordenadas de la cabeza se denomina ojo central. La parte positiva del eje de abscisas se extiende a la derecha y el eje de ordenadas, hacia 72
arriba. El eje positivo de la componente z se introduce en la cabeza. Los valores se dan en metros. ¾ PhysicalEnvironment. El objeto PhysicalEnvironment encapsula toda la información relativa al entorno físico como pueden ser parámetros de calibración de los distintos tipos de rastreo. Estos objetos describen, conjuntamente, la geometría de visualización. El generador de imágenes de Java 3D utiliza esta información para construir las matrices de visualización y de proyección apropiados. El hecho de que estén creados desde un punto de vista geométrico proporciona a estos objetos una gran flexibilidad para generar vistas, lo cual les permite cambiar fácilmente de configuración.
13.4.5 ViewPlatform: Un lugar en el mundo virtual Un nodo hoja ViewPlatform define un sistema de coordenadas y, por lo tanto, un punto de referencia relativo a su origen asociado en el mundo virtual. Este objeto sirve como punto de unión para los objetos de visualización y como base para determinar el punto de vista de la renderización. Los nodos que se sitúan por encima del ViewPlatform en el grafo de escena determinan la posición de dicho ViewPlatform así cómo está orientado dentro del mundo virtual. Si se modifica el objeto Transform3D asociado con un nodo TransformGroup en cualquier lugar por encima de un ViewPlatform, se puede permitir que una aplicación o comportamiento pueda mover dicho ViewPlatform de cualquier forma dentro del mundo virtual. Un VirtualUniverse puede tener varios ViewPlatform, pero un objeto View sólo puede unirse a un único ViewPlatform. Así pues, cada generación de imágenes en un Canvas3D se realiza desde el punto de vista de un único ViewPlatform. Una aplicación puede navegar por el mundo virtual modificando el padre de un objeto ViewPlatform, el objeto TransformGroup. Aplicaciones que pueden modificar la ubicación y orientación de un ViewPlatform son los navegadores, visualizadores de objetos incluso juegos de búsqueda. El control del objeto ViewPlatform puede producir resultados muy útiles e interesantes. Un grafo de escena puede contener varios objetos ViewPlatform. Si un usuario separa un objeto View de un objeto ViewPlatform y, posteriormente, une ese mismo objeto View a otro ViewPlatform diferente, la imagen que se muestre se generará desde el punto de vista del nuevo objeto ViewPlatform.
73
13.4.6 El sistema de coordenadas El modelo básico de visualización consta de ocho o nueve sistemas de coordenadas, dependiendo de si el sistema del usuario es montado “en cabeza” o “en habitación”.
13.4.6.1 Sistema de coordenadas “montados en habitación” El sistema de coordenadas montado en habitación se divide en sistema de coordenadas virtual y sistema de coordenadas físico. Los sistemas de coordenadas situados dentro de la zona gris existen en el mundo virtual y los situados fuera de dicha zona existen en el mundo físico. El sistema de coordenadas de coexistencia existe en ambos mundos. 13.4.6.1.1 Sistemas de coordenadas virtuales Sistema de coordenadas del mundo virtual El sistema de coordenadas del mundo virtual encapsula el sistema de coordenadas unificado para todos los objetos del grafo de escena localizados en el entorno virtual. Para un objeto View dado, el sistema de coordenadas del mundo virtual lo define el objeto Locale que contiene el objeto ViewPlatform unido al objeto View. Como ya se ha comentado, se trata de un sistema de coordenadas diestro. Sistema de coordenadas de ViewPlatform El sistema de coordenadas del objeto ViewPlatform es el sistema de coordenadas local. Sistema de coordenadas de coexistencia Un objetivo fundamental, e implícito, de cualquier modelo de visualización es poder mapear una porción específica del mundo físico en una zona específica del mundo virtual. Una vez establecida esta relación, se puede preguntar dónde está la cabeza o la mano del usuario dentro del mundo virtual o dónde se encuentra un objeto virtual en el mundo físico. De esta forma el usuario físico puede interactuar con objetos propios del mundo virtual y viceversa. Para establecer este mapeado Java 3D define un sistema de coordenadas especial llamado de coexistencia y que se define de tal forma que existe en ambos mundos, el virtual y el físico. El sistema de coordenadas de coexistencia existe en ambos mundos. Las dos transformaciones que pasan del sistema de coordenadas de coexistencia al sistema de coordenadas del mundo virtual y al contrario, disponen de la información necesaria para expandir o contraer el mundo virtual relativo al mundo físico, así como de toda la información necesaria para colocar y orientar el mundo virtual relativamente al mundo físico. Si estas transformaciones se cambian, se modifica también lo que puede ver el
74
usuario. Para mover al usuario a través del mundo virtual se modifican dichas transformaciones. 13.4.6.1.2 Sistemas de coordenadas físicos Sistema de coordenadas de cabeza Este sistema de coordenadas permite que una aplicación disponga de la información relativa a la geometría de la cabeza del usuario. Proporciona información suficiente como para determinar la posición de los ojos y de los oídos. Sistema de coordenadas de pantalla Este sistema de coordenadas se corresponde con el sistema de coordenadas físico del generador de imágenes. Se define de tal forma que su origen se encuentra en la esquina inferior izquierda del área de visualización. Este sistema de coordenadas es diferente tanto del que correspondería a una pantalla a la izquierda como a una pantalla a la derecha. Estos otros sistemas de coordenadas se definen exclusivamente para sistemas montados ‘en cabeza’. Sistema de coordenadas del head tracker Este sistema de coordenadas se corresponde con el sensor de seis grados de libertad unido a la cabeza del usuario. Describe la posición de la cabeza del usuario en cada momento. Sistema de coordenadas de la base del tracker Se corresponde con el emisor asociado con los rastreadores de posición y orientación absolutas. Este sistema de coordenadas suele estar fuertemente unido al mundo físico.
13.4.6.2 Sistemas de coordenadas “montados en cabeza” Estos sistemas de coordenadas también se dividen en físicos y virtuales. En la siguiente figura se muestran todos ellos. Como ocurría con los sistemas de coordenadas “montados en habitación” los localizados en el área gris corresponden al mundo virtual y los que se encuentran fuera de dicha zona corresponden al mundo real. El sistema de coexistencia existe, también aquí, en ambos mundos. Además de dichos sistemas de coordenadas, Java 3D añade dos nuevos sistemas de coordenadas de pantalla, uno para cada ojo del usuario. Sistema de coordenadas de pantalla izquierda y derecha Estos dos sistemas de coordenadas se corresponden con el sistema de coordenadas físico asociado con cada uno de los ojos. Su origen se encuentra en la esquina inferior izquierda de la zona de pantalla. Ambos planos (los de los dos ojos) no tienen por qué estar en paralelo.
75
13.5 RESUMEN En este capítulo, se han analizado de forma general los mecanismos que proporciona el API de Java 3D para la construcción de escenas en tres dimensiones. Aunque se trata de una descripción a grandes rasgos, es suficiente para descubrir toda la potencia que puede obtenerse con esta API. Analizada la entidad de Java 3D y los objetivos que se persiguen con su diseño, el documento se centra en el análisis de los conceptos elementales y la estructura básica en la que se basa esta API, el grafo de escena. A continuación, se describe cómo se estructura el sistema de coordenadas utilizado en la representación de elementos 3D centrándose en la descripción de las coordenadas de alta resolución que permiten ajustar las necesidades de precisión para describir cualquier elemento a modelar (desde una galaxia a un átomo). El grafo de escena proporciona una descomposición del universo virtual en dos grupos principales: la rama de contenidos y la rama de visualización. Basándose en esta separación, el trabajo se divide, de forma lógica, en dos grandes grupos describiendo cada una de dichas ramas. Dentro de la rama de contenidos, se han descrito los mecanismos principales que proporciona Java 3D para la generación de figuras geométricas. En primer lugar, se comentan las clases involucradas en la generación de figuras primitivas (conos, cilindros, esferas...) para luego centrarse en mecanismo más potentes que permiten generar elementos más complejos. En este punto, se ha analizado como Java 3D realiza el tratamiento de puntos para generar elementos de volumen. Para ello, se introduce la clase GeometryArray y sus derivadas describiendo los principios de funcionamiento de dichas clases. Dentro de la generación de contenidos se analiza la utilización de texto 2D y 3D. Además, esta API proporciona mecanismos adicionales de ayuda para la generación de universos virtuales: cargadores de escenas y clases especializadas de tratamiento de puntos (GeometryInfo, NormalGenerator...). Una vez tratados los mecanismos para crear objetos dentro de una escena, se pasa a describir cómo alterar y configurar la apariencia de cada uno de los objetos. El primer elemento sobre el que se trabaja es el fondo de la propia escena, para, a continuación, centrarse en la descripción de los mecanismos para modelar la apariencia del resto de elementos. En este punto se aborda, de forma general, el tema de la gestión de luces y de texturas. Como punto final de la descripción de la rama de contenidos, se introducen los mecanismos para interactuar con el usuario así como para crear movimiento y animación en Java 3D. En este punto, y en primer lugar, se describen ciertos conceptos esenciales que dan soporte tanto a la gestión de la interacción con el usuario como a la generación de animaciones. Entre estos aspectos generales destacar, el concepto de capacidad que define qué características de un objeto podrán modificarse en tiempo de ejecución y cuales no, así como el concepto de comportamiento.
76
Respecto a la interacción con el usuario, se aborda cómo gestionar los dispositivos básicos de interacción (ratón y teclado) y los comportamientos destinados a ello (KeyNavigatorBehavior, MouseBehavior...), aunque Java 3D no está limitado a estos dispositivos. En cuanto al tema de las animaciones, se aborda, principalmente, el tema de los interpoladores y las animaciones basadas en el tiempo, dejando entrever otros aspectos como el morphing. Tras el análisis de la generación de contenido, el siguiente paso es la descripción de todo lo relacionado con la forma en la cual el sistema visualiza dicho contenido. Para ello, se abordan los conceptos principales en los que se basa la rama de visualización que es la que posee todos los parámetros para configurar la forma en la que se mostrarán los objetos. En este apartado, se introducen ciertos conceptos de interés que caracterizan a Java 3D como es el hecho de superar el concepto de cámara como forma tradicional de visualizar un entorno 3D incorporando aspectos más avanzados como son los head trackers que permiten considerar al usuario como parte de la escena 3D controlando en todo momento su posición, y tomando decisiones en base a dicha posición. Se analizar cómo se combina mundo físico y mundo virtual en Java 3D y como a través de un amplio número de sistemas de coordenadas, esta API puede llegar a corresponder de forma precisa ambos mundos.
77
13.6 CONCLUSIONES A lo largo de este trabajo se ha podido comprobar, de forma general, la potencia de Java 3D como entorno para la generación de escenas en tres dimensiones. La verdad es que se podía haber profundizado mucho más en todo lo referente a métodos y clases, pero no se ha considerado oportuno ya que dicho nivel de detalle queda fuera de las pretensiones de este trabajo. Por el contrario, se ha tratado de dar una visión amplia de los diferentes conceptos y elementos involucrados en la generación de entornos en tres dimensiones utilizando Java 3D. La versión de Java 3D que se ha analizado en este documento es la que se ejecuta sobre sistemas gráficos basados en OpenGL con lo cual, aunque existen diferencias inherentes en la filosofía utilizada por ambas APIs, hay elementos (como por ejemplo el modelo de iluminación) que son prácticamente equivalentes. Una diferencia importante entre Java 3D y OpenGL es el modo de realizar tanto las modificaciones como la configuración de la escena. Mientras que en OpenGL las operaciones se hacen en cualquier orden y con actualizar la escena, todo queda en su sitio, en Java 3D es necesario seguir un orden tanto en la creación de escenas como en su modificación. Esto es debido a que Java 3D utiliza una estructura jerarquizada (un grafo de escena) para representar los distintos elementos. El uso del grafo de escena permite una representación gráfica de la escena previa a su generación por parte del sistema. Además, la estructura del grafo de escena hace posible aislar distintos componentes del mismo, trabajar con zonas del gráfico de forma aislada, incluso compilar partes del grafo de forma aislada y, posteriormente, unirlas al grafo de escena en su lugar correspondiente. Por otro lado, Java 3D es un sistema muy orientado a la compatibilidad con otros entornos (es capaz de cargar escenas generadas en diferentes tipos de sistemas) así como a la versatilidad con multitud de dispositivos (su estructura de visualización permite adaptar un mismo grafo de escena a variadas configuraciones físicas realizando las mínimas modificaciones).
78
13.7 BILIOGRAFÍA Y RECURSOS Documentación: -
Pratdepadua J. J. “Programación en 3D con Java 3D”. Editorial Ra-Ma. 2003.
-
Sun Microsystems. Java 3D 1.3 API Documentation (documentation does not include documentation for utilities). Disponible en http://java.sun.com/products/javamedia/3D/forDevelopers/J3D_1_3_API/j3dapi/index.html
-
Sun Microsystems. Java 3D 1.3 API Specification Guide. Disponible en http://java.sun.com/products/javamedia/3D/forDevelopers/J3D_1_3_API/j3dguide/index.html June 2002.
-
Sun Microsystems. Java 3D API Tutorial. Disponible en http://java.sun.com/developer/onlineTraining/java3d/index.html September 2000.
-
Java 3D 1.3.2 API Documentation (include information for utilities). Disponible en http://download.java.net/media/java3d/javadoc/1.3.2/index.html
-
Java 3D FAQ. Disponible en http://wiki.java.net/bin/view/Javadesktop/Java3DFAQ
Ejemplos de código fuente -
Java 3D examples. http://www.java2s.com/Code/Java/3D/Catalog3D.htm
Foros de debate -
Sun Developer Network. Multimedia and Imaging APIs - Java 3D. http://forum.java.sun.com/forum.jspa?forumID=21
-
java.net Forums. Java Desktop Technologies. Java 3D. http://forums.java.net/jive/forum.jspa?forumID=70
79
Otros sitios de interés -
The Java 3D Home Page http://java.sun.com/products/java-media/3D/
-
The Java 3D Graphics Community http://www.j3d.org/
-
The j3d.org Code Repository http://code.j3d.org/
-
Java 3D VRML 97 Loader https://j3d-vrml97.dev.java.net/
-
Project Looking Glass - A Comprehensive Overview of the Technology Disponible en https://lg3d-core.dev.java.net/files/documents/1834/30923/LG3DOverview.pdf Rev. 0.2 March 14, 2006.
-
Getting Started with the Project Looking Glass Developer’s Release https://lg3d.dev.java.net/lg3d-getting-started.html
-
Project Looking Glass Developer’s Guide https://lg3d.dev.java.net/lg3d-developers-guide.html
-
Project Looking Glass Demo Applications https://lg3d-demo-apps.dev.java.net/
-
Project Looking Glass Application Tutorial 1 - An introduction to the lg3d framework https://lg3d.dev.java.net/tutorial/tutorial1.html
-
Project Looking Glass Application Tutorial 2 – Simple manipulations and user interactions https://lg3d.dev.java.net/tutorial/tutorial2.html
-
Project Looking Glass Application Tutorial 3 – Complex manipulations and user interaction https://lg3d.dev.java.net/tutorial/tutorial3.html
-
java.net Forums – Project Looking Glass 3D http://forums.java.net/jive/forum.jspa?forumID=80
80