Una simple rotación del cubo puede hacer que se vea más de una de sus caras. El primer paso es crear la transformación deseada usando un objeto Transform3D. El fragmento de código de la Figura 82 incorpora un objeto TransformGroup en el escenario gráfico para rotar el cubo sobre el eje x. Primero se crea la transformación de rotación usando el objeto rotate de Transform3D, en la linea 24.
Figura 82 Fragmento de código para rotar un objeto
La rotación se especifica usando el método rotX() de la línea 27.
Entonces se crea el objeto
TransformGroup en la línea 31 para contener la transformación de rotación.
Dos parámetros especifican la rotación: el eje de revolución, y el ángulo de rotación.
El eje se elige seleccionando el método apropiado (rotX, rotY o rotZ). El ángulo de rotación es el valor que se le pasa como argumento. Como el ángulo de rotación se especifica en radianes, el valor PI/4 es 1/8 de una rotación completa, o 45 grados. Solamente las líneas 24 y 27 ejecutan la rotación en un eje.
Después de crear el objeto Transform3D, rotate, se usa en la creacción del objeto TransformGroup objRotate (línea 31). El objeto Transform3D se usa en el escenario gráfico. Entonces el objeto objRotate hace que ColorCube sea su hijo (línea 34). A su vez, el objeto objRoot hace a objRotate como su hijo (línea 33). La rama de contenido gráfico ahora incluye un objeto TransformGroup en el camino del escenario gráfico hacia el objeto ColorCube. Cada uno de los caminos del escenario gráfico es necesario. El objeto BranchGroup es el único que puede ser hijo de un Locale.
El objeto TransformGroup es el único que puede cambiar la localización, la orientación, o el tamaño de un objeto visual. En este caso el objeto TransformGroup cambia la orientación. Por supuesto, el objeto ColorCube es necesario para suministrar el objeto visual. A continuación se puede observar el escenario gráfico producido por el fragmento de la Figura 82.
Figura 83 Escenario gráfico para la rotación del cubo
El resultado de la ejecución de la rotación en un eje y al modificar el eje se se puede observar en la siguiente secuencia gráfica.
Figura 84 Resultado de rotar el cubo en X
Figura 85 Resultado de rotar el cubo en Y
Figura 86 Resultado de rotar el cubo en Z
44.1 Combinación de transformaciones
Frecuentemente un objeto visual se traslada y se rota, o se rota sobre dos ejes. En cualquier caso, se especifican dos transformaciones diferentes para un sólo objeto visual. Las dos transformaciones pueden combinarse en una matriz de transformaciones y contenerse en un sólo objeto TransformGroup. Para el ejemplo se pedirá revisar nuevamente el código de la Figura 82, correspondiente al programa HelloJava3Db.java. Hasta el momento nos habíamos fijado solamente en las líneas 24 y 27 para rotar el objeto visual en un solo eje, al incluir las demás líneas se obtendrá una combinación de rotaciones.
Para crear estas dos rotaciones simultáneas se requiere combinar dos objetos Transform3D de rotación. El ejemplo rota el cubo sobre los ejes x e y. Se crean dos objetos Transform3D, uno por cada rotación (líneas 24 y 25). Las rotaciones individuales se especifican para los dos objetos TransformGroup (líneas 27 y 28). Luego las rotaciones se combinan mediante la multiplicación de los objetos Transform3D (línea 29). La combinación de las dos transformaciones se carga en el objeto TransformGroup (línea 31).
El código completo del ejemplo HelloJava3Db.java es el siguiente: /* @(#)HelloJava3Db.java 1.1 00/09/22 13:55
* Copyright (c) 1996-2000 Sun Microsystems, Inc. All Rights Reserved. * HelloJava3Db dibuja un cubo simple rotado 45° en x y 36° en y
*/ import java.applet.Applet; import java.awt.BorderLayout; import java.awt.Frame; import java.awt.event.*; import java.awt.GraphicsConfiguration; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.*; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*;
public class HelloJava3Db extends Applet {
public BranchGroup createSceneGraph() { // Crea la raíz del árbol
BranchGroup objRoot = new BranchGroup();
// El objeto rotate contiene la matriz de transformación Transform3D rotate = new Transform3D();
Transform3D tempRotate = new Transform3D();
rotate.rotX(Math.PI/4.0d); tempRotate.rotY(Math.PI/5.0d); rotate.mul(tempRotate);
TransformGroup objRotate = new TransformGroup(rotate);
objRoot.addChild(objRotate);
objRotate.addChild(new ColorCube(0.4));
// Compila la escena gráfica objRoot.compile();
return objRoot;
// Crea una escena simple relacionada con el universo virtual public HelloJava3Db() {
setLayout(new BorderLayout());
GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
Canvas3D canvas3D = new Canvas3D(config); add("Center", canvas3D);
BranchGroup scene = createSceneGraph();
SimpleUniverse simpleU = new SimpleUniverse(canvas3D);
simpleU.getViewingPlatform().setNominalViewingTransform();
simpleU.addBranchGraph(scene); } // Fin del constructor HelloJava3Db
public static void main(String[] args) {
Frame frame = new MainFrame(new HelloJava3Db(), 256, 256); } // Fin del método main
} // Fin de la clase HelloJava3Db
En la Figura 87 se puede ver el escenario gráfico creado en HelloJava3Db.java. La rama de vista gráfica es la misma producida en HelloJava3Da, que está construida por un SimpleUniverse y representada por una gran estrella. La rama de contenido gráfico ahora incluye un TransformGroup en el camino del escenario gráfico hacia el objeto ColorCube. En la Figura 88 se puede observar el resultado de la ejecución.
Figura 87 Escenario gráfico para varias
transformaciones Figura 88 Ejecución de HelloJava3Db con rotación en X e Y
44.2 Capacidades y Rendimiento
El escenario gráfico construido por un programa Java 3D podría usarse directamente para renderizar. Sin embargo, la representación no es muy eficiente. La flexibilidad construida dentro de cada objeto escenario gráfico (que no se van a discutir en este tutorial) crean un representación sub-optima del universo virtual. Para mejorar el rendimiento de la renderización se usa una representación más eficiente del universo virtual.
Java 3D tiene una representación interna para una universo virtual y los métodos para hacer la conversión. Hay dos formas para hacer que el sistema Java 3D haga la conversión de la representación interna. Una forma es compilar todas las ramas gráficas. La otra forma es insertar una rama gráfica en un universo virtual para darle vida.
Compilar Contenidos
El objeto BranchGroup tiene un método compilador. Llamando a este método se convierte la rama gráfica completa que hay debajo del BranchGroup a la representación interna de Java 3D de la rama gráfica. Además de la conversión, la representación interna podría optimizarse de una o varias maneras.
Las posibles optimizaciones no se especifican en el API Java 3D. Sin embargo, se puede ganar en eficiencia de varias formas. Una de las posibles optimizaciones es combinar TransformGroups con caminos de escenario gráfico. Por ejemplo, si un
escenario gráfico tiene dos objetos TransformGroup en una relacion padre-hijo pueden ser representados por un objeto TransformGroup. Otra posibilidad es combinar objetos Shape3D que tienen una relación estática física. Estos tipos de optimizaciones se hacen posibles cuando las capacidades no se configuran.
La Figura 89 presenta una representación conceptual de la conversión a una representación más eficiente. El escenario gráfico del lado izquierdo es compilado y transformado en la representación interna mostrada en el lado derecho. La figura sólo representa el concepto de representación interna, no como Java 3D realmente lo hace.
Figura 89 Representación conceptual del proceso de compilar un escenario gráfico
Capacidades
Una vez que una rama gráfica empieza a vivir o es compilada el sistema de renderizado Java 3D la convierte a una representación interna más eficiente. El efecto más importante de esta conversión es la mejora del rendimiento de renderizado.
Pero también tiene otros efectos, uno de ellos es fijar el valor de transformaciones y otros objetos en el escenario gráfico. A menos que especificamente se le proporcionen al programa, este no tendrá la capacidad de cambiar los valores de los objetos del escenario gráfico una vez que estén vivos.
Hay casos en que un programa necesita la capacidad de cambiar estos valores después de que estén vivos. Por ejemplo, cambiar el valor de un objeto TransformGroup crea animaciones. Para que esto suceda, la transforamción debe
poder cambiar después de estar viva. La lista de parámetros a los que se puede acceder, y de que forma, se llama capacidades del objeto.
Cada SceneGraphObject tiene un conjunto de bits de capacidad. Los valores de estos bits determinan que capacidades existen para el objeto después de compilarlo o de darle vida. El conjunto de capacidades varía con la clase. SceneGraphObject es la superclase de casi cualquier clase usada para crear un escenario gráfico, incluyendo Group, Leaf, y NodeComponent.
A continuación se presenta la lista parcial de métodos de SceneGraphObject. void clearCapability(int bit) Borra el bit de capacidad especificado. boolean getCapability(int bit) Recupera el bit de capcidad especificado. void setCapability(int bit) Configura el bit de capacidad especificado.
Como ejemplo, para poder leer el valor de la transformación representada por un objeto TransformGroup, esta capacidad debe activarse antes de compilarlo o darle vida. De forma similar, para poder cambiar el valor de la transformación en un objeto TransformGroup, su capacidad de escribir transformación debe configurarse antes de compilarlo o darle vida. Intentar hacer un cambio en un objeto vivo o compilado para el que la propiedad adecuada no se ha configurado resultará en una excepción.
En la siguiente sección, las animaciones se crean usando una transformación de rotación que varía con el tiempo. Para que esto sea posible, el objeto TransformGroup debe tener su capacidad ALLOW_TRANSFORM_WRITE activada antes de que sea compilado o se le de vida.
A continuación se presenta la lista parcial de capacidades de TransformGroup. Las dos capacidades listadas aquí son las únicas definidas por TransformGroup. Éste hereda varias capacidades de sus clases ancestros: Group y Node. La configuración de capacidades se puede seleccionar, eliminar o recuperar usando los métodos definidos en SceneGraphObject.
ALLOW_TRANSFORM_READ Especifica que el nodo TransformGroup permite acceder a la información de transformación de su objeto.
ALLOW_TRANSFORM_WRITE Especifica que el nodo TransformGroup permite escribir la información de transformación de su objeto.
Las capacidades también controlan el acceso a otros aspectos de un objeto TransformGroup. Los objetos TransformGroup heredan configuración de
capacidades de sus clases ancestros: Group y Node. En el siguiente bloque de referencia se pueden ver ver algunas de esas capacidades.
Lista Parcial de Capacidades de Group: TransformGroup hereda varios bits de capacidades de sus clases ancestros.
ALLOW_CHILDREN_EXTEND Permite que se puedan añadir hijos al nodo Group después de que esté compilado o vivo.
ALLOW_CHILDREN_READ Permite que se puedan leer las referencias a los hijos del nodo Group después de que esté compilado o vivo.
ALLOW_CHILDREN_WRITE Permite que se puedan escribir las referencias a los hijos del nodo Group después de que esté compilado o vivo.