Está en la página 1de 51

Introduccin a Java 3D

Lorenzo Martn Edreira


Rubn Melcn Faria

1 INTRODUCCIN
1.1Qu es la API Java 3D API?
La API Java 3D es una jerarqua de clases java que sirven como interfaz a sistemas grficos de 3
dimensiones de imagen y sonido. Los programadores trabajan con constructores de alto nivel para
crear y manipular objetos 3D. Estos objetos residen en un universo virtual que es dibujado para su
presentacin a los usuarios.
Un programa Java 3D crea instancias de objetos Java 3D y los coloca en la estructura de datos de
objetos grficos de la escena. El grfico de la escena est organizado en forma de rbol y especifica
completamente el contenido del universo virtual, y cmo este es dibujado.

1.2 La API Java 3D


Todos los programas Java 3D estn, por lo menos parcialmente, formados por objetos de la
jerarqua de clases Java 3D. Esta coleccin de objetos describe un universo virtual, el cual va a ser
dibujado. La API define sobre 100 clases presentadas en el paquete javax.media.j3d. Estas clases
son referidas comnmente como las clases ncleo de Java 3D
En adiccin a las clases ncleo de Java 3D nos encontraremos con las clases de utilidades que
incluyen cargadores de contenido, clases de geometra ... que suponen una adiccin conveniente y
potente a las clases de bajo nivel que componen la clases ncleo de Java 3D. Las clases de
utilidades las encontraremos en el paquete com.sun.j3d.utils. Como se muestra en el nombre del
paquete, estas clases no pertenecen a la especificacin de la API Java 3D, y son clases propias de la
implementacin de referencia realizada por Sun Microsystems.
Adems de los paquetes de clases ncleo de Java 3D y las clases de utilidades proporcionadas
por Sun Microsystems, nos encontraremos con clases del paquete java.awt, que nos definen clases
para crear un ventana en la que mostrar el grfico, y el paquete javax.vecmatch ,que definen clases
matemticas de puntos de vectores, matrices y otros objetos matemticos.
La API Java 3D no es un conjunto de paquetes y clases que vengan de forma predeterminada en
la distribucin Java normal (J2SE), sino que es una extensin que debemos instalar de forma aparte.
En nuestro caso utilizaremos la versin Java 3D 1.3.1 con interfaz a OpenGL y el J2SE 1.4.2 en una
plataforma Microsoft Windows. A parte del SDK Java3D para MS Windows, tambin podremos
descargarnos la versin con interfaz a DirectDraw, tambin para Microsoft Windows y la versin
para Solaris (versin SPARC) de Java 3D con interfaz a OpenGL.
Los archivos que nos encontraremos en nuestra distribucin son:
<JREDIR>\bin\J3D.dll
<JREDIR>\bin\j3daudio.dll
<JREDIR>\bin\J3DUtils.dll
<JREDIR>\lib\ext\vecmath.jar
<JREDIR>\lib\ext\j3dcore.jar
<JREDIR>\lib\ext\j3daudio.jar

<JREDIR>\lib\ext\j3dutils.jar
<JDKDIR>\j3d-utils-src.jar
<JDKDIR>\demo\java3d
Una vez instalado el paquete, ya podremos desarrollar nuestras aplicaciones Java3D, pero antes
daremos unas nociones bsicas de la arquitectura de construccin de los universos virtuales en Java
3D.

1.3 Estructura de la escena de un grfico


Un universo virtual Java 3D se crea a partir de un escenario grfico. Un escenario grfico se crea
usando instancias de clases Java 3D. El conjunto de objetos grficos est formado por objetos que
definen la geometra, sonido, luces, localizacin, orientacin y apariencia de objetos de audio y
visuales.
Una definicin de un conjunto de objetos grficos es una estructura de datos compuesto por
nodos y arcos. Un nodo es una elemento de datos y un arco es una relacin entre nodos. Los nodos
en el diagrama del escenario son las instancias de las clases Java3D. Los arcos representan los dos
tipos de relaciones (Padre-Hijo y Referencia) entre las instancias Java 3D.
Las relaciones Padre-Hijo forman una relacin entre los objetos del escenario, y las relaciones de
referencia asocian los nodos NodeComponent con un nodo del escenario definiendo la geometra y
atributos de la apariencia usados para dibujar los objetos visuales

1.4 Instrucciones para escribir Programas Java 3D


Para escribir programas que utilicen las clases Java 3D es recomendable seguir una secuencia de
pasos lgicos que nos permitirn una mejor estructuracin de nuestros programas y el uso de un
mtodo de construccin comn en todos los programas. Los pasos para construir un programa Java
3D con siete:
1) Crear un objeto Canvas3D
2) Crear un objeto VirtualUniverse
3) Crear un objeto Locale, atacando al VirtualUniverse
4) Construir un grfico de la rama de visualizacin
a) Crear un objeto vista
b) Crear un objeto ViewPlatform
c) Crear un objeto PhysicalBody
d) Crear un objeto PhysicalEnvisonment
e) Atacar ViewPlatform, PhysicalBody, PhysicalEnvironment y Canvas3D al objeto View
5) Construir un grfico de la rama del contenido
6) Compilar las ramas
7) Insertar las distintas partes que componen el escenario en el Locale

1.4.1 Una receta simple para escribir los programas Java 3D

La mayora de nuestros programas Java 3D utilizan una estructura en el proceso de visualizacin


casi idntica. Debido a esto, Sun Microsystems ha provisto una clase Java que nos crear todo el
universo virtual, y nos ahorrar tiempo de codificacin.
Esta clase, llamada SimpleUniverse, es el punto de inicio ms fcil para empezar a programar,
porque nos podremos olvidar de las estructuras de visualizacin y nos podremos concentrar en las
estructuras de contenido. Un inconveniente que tendremos con esta clase es que no podremos tener
mltiples vistas del universo virtual, y lo que no debemos de olvidar, esta clase no forma parte de la
especificacin Java 3D, con lo que no tenemos asegurado que se ejecuten nuestros programas en
otras implementaciones.
Con la clase SimpleUniverse nuestro esquema de construccin de programas Java 3D nos
quedar:
1) Crear un objeto Canvas3D
2) Crear un objeto SimpleUniverse que haga referencia al objeto Canvas3D
a) Personalizar SimpleUniverse
3) Construir la rama de contenido (BranchGroup)
4) Compilar el grfico de la rama de contenido
5) Insertar las estructuras de la rama de contenido en el Locale del SimpleUniverse
Una vez creados los objetos Canvas3D y SimpleUniverse, el siguiente paso es la creacin de las
estructuras de la rama de contenido. Despus de crear la rama de contenido, esta ser insertada con
el mtodo addBranchGraph(BranchGroup) de SimpleUniverse.
En el objeto BranchGroup definiremos todos los objetos Java 3D que queremos que se
encuentren contenidos en nuestro escenario, as como las clases de comportamiento que queremos
que afecten a nuestros objetos. Por ejemplo, el objeto Transform3D nos permitir rotar, escalar y
trasladar nuestros objetos, y la clase TransformGroup nos permitir agrupar las clases de
comportamiento. La forma de utilizar estas clases de comportamiento ser:
1) Crear el objeto Transform3D
2) Crear los objetos 3D de la escena
3) Aadir los objetos Transform3D a un TransformGroup
4) Aadir los objetos 3D a TransformGroup
5) Aadir TransformGroup al objeto BranchGroup.

1.5 Capacidades y Rendimiento


Una vez que tenemos definida nuestro escenario debemos de compilarlo a travs del mtodo
compile() de BranchGroup que nos permitir realizar optimizaciones de nuestro escenario. En esta
compilacin lo que se suele realizar es la agrupacin de los objetos Transform3D de un
TransformGroup a una representacin interna optimizada.

Pero un efecto lateral de la compilacin es que las capacidades del TransformGroup de modificar
su comportamiento se ve limitado. La solucin que utilizaremos para evitar este comportamiento
ser la de establecer las capacidades del objeto TransformGroup para notificar al compilador de que
queremos permitir ciertos comportamientos en nuestros objetos. Todo esto lo realizaremos a travs
del mtodo setCapability(Capability), donde podremos especificar los comportamientos que
queremos permitir. Algunas de las capacidades que tendremos disponibles son:
1) ALLOW_TRANSFORM_READ - Acceso de lectura del objeto TransformGroup
2) ALLOW_TRANSFORM_WRITE - Acceso de escritura del objeto TransformGroup
3) ALLOW_CHILDREN_EXTEND - Se permiten aadir ms nodos hijo
4) ALLOW_CHILDREN_READ - Acceso de lectura de los nodos hijo
5) ALLOW_CHILDREN_WRITE - Acceso de escritura de los nodos hijo

1.6 Animacin
En Java 3D, Behaviour es una clase para especificar animaciones o interacciones de objetos
visuales, capaz de cambiar virtualmente cualquier atributo de un objeto visual. Un programador
puede usar un nmero predefinido de comportamientos o especificar uno personalizado. Una vez
que se especifica un comportamiento para un objeto visual, el sistema Java 3D actualiza la posicin,
orientacin, color u otros atributos del objeto visual automticamente.
La diferencia entre animacin e interaccin est en cuando el comportamiento es activado en
respuesta al paso del tiempo o en respuesta a las actividades del usuario.
Para especificar un comportamiento para un objeto visual, el programador crea los objetos que
especifican el comportamiento, aaden al objeto visual a la escena del grfico, y se construyen las
referencias apropiadas entre los objetos del escenario y los objetos Behaviour.
Un problema que nos encontraremos al utilizar los comportamientos es que tendremos que
especificar una regin que haga de lmite para el comportamiento. Este lmite se llama regin de
planificacin. Un comportamiento no est activo a menos que el volumen de activacin de la
plataforma de visin tenga un punto de interseccin con la regin de planificacin de un objeto
Behavior.
Una de las clases de comportamiento predefinidas que nos podremos encontrar es la clase
Interpolator. Esta clase est basada en una funcin de tiempo en la que el objeto Interpolator
manipula los parmetros de un objeto del grfico del escenario. Por ejemplo, RotationInterpolator
manipula la rotacin especificada por un TransformGroup para afectar a la rotacin de los objetos
visuales hijos del TransformGroup.
Los pasos para especificar una animacin con un objeto Interpolator son los siguientes:
1) Crear un TransformGroup con la capacidad ALLOW_TRANSFORM_WRITE
2) Crear un objeto Alpha que especifique los parmetros de tiempo
3) Crear un objeto Interpolator que haga referencia a los objetos Alpha y TransformGroup
5) Especificar una regin de planificacin

6) Hacer el comportamiento hijo del TransformGroup

1.7 Ejemplo
Para ver el funcionamiento de todas las clases mencionadas anteriormente, veremos un pequeo
programa en el que utilizaremos todos los puntos anteriores. El programa que crearemos crear un
objeto predefinido en el paquete de utilidades que nos define un cubo con un color para cada cara.
Adems a la escena le aadiremos un rotacin dependiente del tiempo y un lmite para el
comportamiento definido por una esfera de radio 100 y centrado en el punto (0,0,0).

package es.udc.fi.gc;
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
public class Hello extends Applet {
private SimpleUniverse u = null;
public BranchGroup createSceneGraph() {
// Crear la raiz de la rama de objetos grficos
BranchGroup objRoot = new BranchGroup();

// Crear el nodo TransformGroup y engancharlo a la raz


// Habilitar la capacidad TRANSFORM_WRITE para que se pueda modificar
// en tiempo de ejecucin.
TransformGroup objTrans = new TransformGroup();
objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
objRoot.addChild(objTrans);
// Crear un objeto Shape3D y aadirlo a la escena.
objTrans.addChild(new ColorCube(0.4));
// Crear un objeto Behavior que realizar las operaciones
// deseadas en la transformada especificada y aadirlo a la escena
Transform3D yAxis = new Transform3D();
Alpha rotationAlpha = new Alpha(-1, 4000);
RotationInterpolator rotator =
new RotationInterpolator(
rotationAlpha,
objTrans,
yAxis,
0.0f,
(float) Math.PI * 2.0f);
BoundingSphere bounds =
new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
rotator.setSchedulingBounds(bounds);
objRoot.addChild(rotator);
// Compilamos para optimizar
objRoot.compile();
return objRoot;
}
public Hello() {
}
public void init() {
setLayout(new BorderLayout());
GraphicsConfiguration config =
SimpleUniverse.getPreferredConfiguration();

Canvas3D c = new Canvas3D(config);


add("Center", c);
// Creamos una escena y atacarla al universo virtual
BranchGroup scene = createSceneGraph();
u = new SimpleUniverse(c);
// Mueve el punto de vista un poco atrs para ver los objetos
u.getViewingPlatform().setNominalViewingTransform();
u.addBranchGraph(scene);
}
public void destroy() {
u.cleanup();
}
//
// El siguiente cdigo permite a HelloUniverse ejecutarse como una aplicacin
// y como un applet
//
public static void main(String[] args) {
new MainFrame(new Hello(), 256, 256);
}
}

2. CREANDO GEOMETRAS
En el captulo 1 exploramos los conceptos bsicos de la construccin de un universo virtual Java
3D, concentrndonos en especificar las transformadas y comportamientos, y para demostrar su
construccin y funcionamiento construimos un pequeo programa. Pero en el programa que
construimos slo haba un figura, y era un cubo de colores que ya vena preconstruido en las clases
de utilidades de la distribucin de Java 3D, y a la cual no le podamos especificar ni la apariencia ni
el color.
En este captulo veremos que hay tres formas de construir los objetos que queremos representar y
que podremos construir a travs de objetos ya predefinidos (cubos, conos, esferas ...), a travs de
coordenadas de los vrtices o a travs de cargadores de geometras.

2.1 Sistemas de coordenadas del Mundo Virtual


En nuestros programas Java 3D una instancia de VirtualUniverse sirve como la raz del escenario
de los grfico. El trmino universo virtual se refiere al espacio virtual de 3 dimensiones donde se
sitan los objetos 3D. Cada objeto Locale establece un sistema de coordenadas cartesianas en el
universo virtual. Esto es, un objeto Locale sirve como punto de referencia para los objetos visuales
en nuestro universo virtual. Con un Locale en un SimpleUniverse existe un sistema de coordenadas
en el universo virtual.
El sistema de coordenadas de universo virtual Java es de mano derecha. El eje X es positivo a la
derecha, el eje Y es positivo hacia arriba y el eje X es positivo hacia el usuario.

2.2 Definiciones bsicas de Objetos visuales

2.2.1 Shape3D

Un nodo Shape3D define un objeto visual genrico. La clase Shape3D no contiene informacin
sobre el color o la forma de un objeto visual, sino que esta informacin se almacena en los objetos
NodeComponent referenciados por el objeto Shape3D. Un objeto Shape3D puede referenciar a un
componente del nodo Geometry y/o Appearance.

2.2.2 Componentes Nodo

Los objetos NodeComponent contienen la especificacin de los atributos del objeto visual. Cada
una de las subclases de NodeComponent define ciertos atributos visuales como la apariencia,
geometra, material, texturas ...
2.2.3 Definiendo las Clases de objetos visuales

El mismo objeto visual puede encontrarse varias veces en nuestra escena, por lo que tendr
sentido definir una clase que cree el objeto visual en vez de construir cada objeto visual desde el
principio.
La estructura de la construccin de un objeto visual es la siguiente:
public class VisualObject extends Shape3D {
private Geometry voGeometry;
private Appearance voAppearance;
// Creamos el objeto Shape3D con la geometra y apariencia
public VisualObject(){
voGeometry = createGeometry();
voAppearance = createAppearance();
this.setGeometry(voGeometry);
this.setAppearance(voAppearance);
}
....
}

2.3 Clases de utilidades geomtricas


Las distribucin que nos ofrece Sun Microsystems viene acompaada de un paquete de utilidades
que nos suministra clases de objetos visuales que representan primitivas de objetos del mundo real.
Estas clases nos proporcionarn una forma sencilla de crear estos objetos y pudiendo especificar la
apariencia deseada.
Las primitivas predefinidas que nos encontraremos las tendremos en el paquete
com.sun.j3d.utils.geometry y corresponden a los objetos que representan a un cubo, cono, cilindros
y esferas:
com.sun.j3d.utils.geometry.Box
com.sun.j3d.utils.geometry.Cone
com.sun.j3d.utils.geometry.Cilinder
com.sun.j3d.utils.geometry.Sphere
La construccin de una escena con uno de estos componentes es muy fcil, slo tenemos que
cambiar los colores para que nuestra figura no se confunda con el fondo y despus seguir los pasos
de la clase Hello del primer captulo:

package es.udc.fi.gc;

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.Cone;
import com.sun.j3d.utils.universe.*;

import javax.media.j3d.*;
public class HelloCone extends Applet {
private SimpleUniverse u = null;
public BranchGroup createSceneGraph() {
// Crear la raiz de la rama del grfico
BranchGroup objRoot = new BranchGroup();
// Crear un objeto Shape3D y aadirlo a la escena.
Appearance apariencia = new Appearance();
apariencia.setColoringAttributes(new ColoringAttributes(0.3f, 1.0f,1.0f,
ColoringAttributes.SHADE_FLAT));
Node node = new Cone(0.5f,0.3f,apariencia);
objRoot.addChild(node);
// Compilar para optimizar
objRoot.compile();
return objRoot;
}
public HelloCone() {
}
public void init() {
setLayout(new BorderLayout());
GraphicsConfiguration config =
SimpleUniverse.getPreferredConfiguration();
Canvas3D c = new Canvas3D(config);
add("Center", c);
// Crear una escena y atacarla al universo virtual
BranchGroup scene = createSceneGraph();
u = new SimpleUniverse(c);
// Mueve el punto de vista un poco atrs para ver los objetos
u.getViewingPlatform().setNominalViewingTransform();
u.addBranchGraph(scene);

}
public void destroy() {
u.cleanup();
}
public static void main(String[] args) {
new MainFrame(new HelloCone(), 256, 256);
}
}

2.4 Clases matemticas


Para crear objetos visuales necesitaremos a la clase Geometry y a sus subclases. Muchas de las
subclases de Geometry describen primitivas basndose en otras primitivas ms sencillas basadas en
la definicin a partir de sus vrtices, como sucede con los puntos, lneas y polgonos. Pero antes de
meternos con estas clases necesitaremos de otras clases matemticas que nos ayudarn a definir
nuestros objetos.
Las clases matemticas que necesitaremos las encontraremos en el paquete javax.vecmatch.* y
las clases que ms utilizaremos son aquellas que definen puntos (Pointf, Pointd), colores (Colorf,
Colord), vectores (Vectorf, Vectord), coordenadas de texturas (TexCoordf, TextCoordd) y
cuarteniones (Quadd y Quadf).

2.5 Clases de geometra


En los grficos en 3D todo est modelado y dibujado con datos basados en conjuntos de vrtices.
Para realizar la construccin de objetos complejos, la API Java 3D nos proporciona una clase,
GeometryArray, con el que podremos construir objetos complejos basndonos en sus vrtices como
puntos, lneas, tringulos y polgonos en general. Pero adems de GeometryArray tendremos otras
clases que extienden de ella y con las que podremos especificar otros parmetros, como la
reutilizacin de los vrtices. Las clases padres en la construccin de objetos son GeometryArray,
GeometryStripArray e IndexedGeometryArray.
Las subclases de GeometryArray y una representacin de son comportamiento son:

Las subclases de GeometryStripArray y una representacin grfica de ellas son:

Las subclases de IndexedGeometryArray nos proporcionarn una forma de eliminar los vrtices
redundantes, aunque con la penalizacin de tener que construir arrays de datos que contengan los
ndices para las coordenadas, ndices, color, texturas y normales. Lo nico que deberemos tener en
cuenta es que la matrices de ndices podrn tener mltiples referencias al mismo vrtice en los
arrays de datos. Las clases que tendremos disponibles son IndexedGeometryArray,
IndexedPointArray, IndexedLineArray, IndexedTriangleArray, IndexedQuadArray,
IndexedGeometryStripArray, IndexedLineStripArray, IndexedTriangleStripArray y
IndexedTriangleFanArray.
EL siguiente ejemplo muestra la construccin de dos rectas y un tringulo con los vrtices de
colores distintos en nuestro escenario.

package es.udc.fi.gc;
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
public class BasicFigures extends Applet {
private SimpleUniverse u = null;
public BranchGroup createSceneGraph() {
BranchGroup objRoot = new BranchGroup();
LineArray line1 = new LineArray(2, LineArray.COORDINATES);
line1.setCoordinate(0, new Point3f(0.0f, 0.0f, 0.0f));
line1.setCoordinate(1, new Point3f(0.3f, 0.0f, 0.0f));
LineArray line2 = new LineArray(2, LineArray.COORDINATES);
line2.setCoordinate(0, new Point3f(0.0f, 0.3f, 0.0f));
line2.setCoordinate(1, new Point3f(0.1f, 0.0f, 0.3f));
TriangleArray triangle = new TriangleArray(3, TriangleArray.COORDINATES|
TriangleArray.COLOR_3);

triangle.setCoordinate(0, new Point3f (-0.3f, 0.5f, 0.0f));


triangle.setCoordinate(1, new Point3f (-0.65f, -0.6f, 0.0f));
triangle.setCoordinate(2, new Point3f (0.0f, -0.5f, 0.0f));
triangle.setColor(0, new Color3f(1.0f, 0.0f, 0.0f));
triangle.setColor(1, new Color3f(1.0f, 1.0f, 0.0f));
triangle.setColor(2, new Color3f(1.0f, 0.0f, 1.0f));
objRoot.addChild(new Shape3D(line1));
objRoot.addChild(new Shape3D(line2));
objRoot.addChild(new Shape3D(triangle));
// Compilamos para optimizar
objRoot.compile();
return objRoot;
}
public BasicFigures() {
}
public void init() {
setLayout(new BorderLayout());
GraphicsConfiguration config =
SimpleUniverse.getPreferredConfiguration();
Canvas3D c = new Canvas3D(config);
add("Center", c);
// Crear una escena y atacarla al universo virtual
BranchGroup scene = createSceneGraph();
u = new SimpleUniverse(c);
// Mueve el punto de vista un poco atrs para ver los objetos
u.getViewingPlatform().setNominalViewingTransform();
u.addBranchGraph(scene);
}
public void destroy() {
u.cleanup();
}

public static void main(String[] args) {


new MainFrame(new BasicFigures(), 256, 256);
}
}

2.6 Apariencia y atributos


Los objetos Shape3D pueden hacer referencia a objetos Geometry y Appearance. Tal como
hemos visto, los objetos Geometry especifican la informacin por vrtices de los objetos visuales.
La informacin de cada vrtice tambin puede especificar la informacin de color, pero si queremos
efectos ms sofisticados tendremos que recurrir al nodo Appearance.
Un objeto Appearance no contiene informacin de como debera de ser un objeto Shape3D, sino
que la informacin que contiene es la que dice dnde encontrar los datos de apariencia. Esto es,
dentro del objeto Appearance no encontraremos especificada la informacin de la apariencia, sino
que tendremos las referencias a los objetos atributos que contienen la informacin.
Los objetos de atributos que encontraremos en la clase Appearance son:

PointAttributes

LineAttributes

PolygonAttributes

ColoringAttributes

TransparencyAttributes

RenderingAttributes

Material

TextureAttributes

Texture

TexCoodGeneration

2.7 Cargadores de contenido


Adems de las clases de para crear geometras que hemos visto, tambin habamos mencionado
al principio de este captulo que existan los cargadores de clases. Un cargador de clase son
cargadores de objetos 3D definidos en archivos construidos con herramientas de terceras compaas.
Como ejemplo, mencionaremos que existen cargadores para archivos generados con el 3D-Studio,
AutoCAD, VRML, WaveFrom, LightWare ... que son gratuitos y que podremos descargar a travs
de la pgina de enlaces de Java 3D.

2.8 Otros elementos de contenido


Otros objetos que podremos aadir a nuestro escenario pueden ser texto en 2 dimensiones
(Text2D), texto en 3 dimensiones (Text3D) y colores de fondo (BackGround). Estos objetos son
muy fciles de utilizar, y nos sern muy tiles de utilizar en nuestras escenas.

Con el objeto Text2D tendremos que especificar el texto que deseamos visualizar junto con los
atributos de color, tamao y fuente al aadirlo al BranchGroup. Ejemplo:

package es.udc.fi.gc;
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.Text2D;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
public class HelloText2D extends Applet {
private SimpleUniverse u = null;
public BranchGroup createSceneGraph() {
// Crear la raiz de la rama del grfico
BranchGroup objRoot = new BranchGroup();
Text2D text2D = new Text2D("Texto en 2D", new Color3f(0.8f, 1.0f, 1.0f),
"Helvetica", 21, Font.BOLD);
objRoot.addChild(text2D);

// Compilar para optimizar


objRoot.compile();
return objRoot;
}

public HelloText2D() {
}
public void init() {
setLayout(new BorderLayout());
GraphicsConfiguration config =
SimpleUniverse.getPreferredConfiguration();
Canvas3D c = new Canvas3D(config);
add("Center", c);
// Crear una escena y atacarla al universo virtual
BranchGroup scene = createSceneGraph();
u = new SimpleUniverse(c);
// Mueve el punto de vista un poco atrs para ver los objetos
u.getViewingPlatform().setNominalViewingTransform();
u.addBranchGraph(scene);
}
public void destroy() {
u.cleanup();
}
public static void main(String[] args) {
new MainFrame(new HelloText2D(), 256, 256);
}
}

En el caso del objeto Text3D tendremos que especificar una extrusin a lo largo del eje Z en el
constructor de la fuente (Font3D).
Y con el fondo necesitaremos especificar el color deseado y los lmites dentro de los que se
aplicar el nuevo color de fondo. En el siguiente cdigo veremos un ejemplo de estas dos ltimas
caractersticas juntas.

package es.udc.fi.gc;
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
public class HelloText3D extends Applet {
private SimpleUniverse u = null;
public BranchGroup createSceneGraph() {
// Crear la raiz de la rama del grfico
BranchGroup objRoot = new BranchGroup();
Background bg= new Background();
bg.setColor(0.3f, 0.6f,0.0f);
bg.setApplicationBounds(new BoundingSphere(new Point3d(),100.0f));
Font3D font3D = new Font3D(new Font("Helvetica", Font.PLAIN, 6), new
FontExtrusion());
Text3D text3D =
new Text3D(font3D,
"Texto en 3D",
new Point3f(-12.0f, 0.8f, -50.0f));

Shape3D textShape = new Shape3D(text3D);


objRoot.addChild(textShape);
objRoot.addChild(bg);
// Compilar para optimizar
objRoot.compile();
return objRoot;
}
public HelloText3D() {
}
public void init() {
setLayout(new BorderLayout());
GraphicsConfiguration config =
SimpleUniverse.getPreferredConfiguration();
Canvas3D c = new Canvas3D(config);
add("Center", c);
// Crear una escena y atacarla al universo virtual
BranchGroup scene = createSceneGraph();
u = new SimpleUniverse(c);
// Mueve el punto de vista un poco atrs para ver los objetos
u.getViewingPlatform().setNominalViewingTransform();
u.addBranchGraph(scene);
}
public void destroy() {
u.cleanup();
}
public static void main(String[] args) {
new MainFrame(new HelloText3D(), 256, 256);
}
}

2.9 Transformaciones bsicas


Una vez que tenemos nuestros objetos visuales creados, lo siguiente que desearemos hacer ser
aplicarle alguna transformacin para colocarlos en el lugar deseado de nuestro escenario. En Java
3D existe una clase de transformaciones, Transform3D, y en ella aplicaremos las operaciones que
deseemos, como rotaciones, escalados y translacciones. Una vez aplicada la operacin deseada,
aadiremos el objeto Transform3D a un TransformGroup, que es una objeto que utilizaremos para
agrupar a las transformaciones. Una vez que tenemos el TransformGroup, le aadiremos los objetos
a los que queremos aplicar las transformaciones.
Los mtodos para aplicar las transformaciones en Transform3D son rotX(double), rotY(double),
rotZ(double), setTranslation(Vector3*) y setScale(Vector3d). Adems de estos mtodos tambin
dispondremos de otros que nos permitirn agrupar en el propio Transform3D las transformaciones,
multiplicando directamente las matrices de transformacin, mul(Transform3D), o aplicndole otra
transformacin, add(Transform3D).
En el siguiente cdigo crearemos un tringulo de colores y lo rotaremos sobre el eje Y.

package es.udc.fi.gc;
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
public class BasicTransform extends Applet {
private SimpleUniverse u = null;

public BranchGroup createSceneGraph() {


BranchGroup objRoot = new BranchGroup();
TriangleArray triangle = new TriangleArray(3, TriangleArray.COORDINATES|
TriangleArray.COLOR_3);
triangle.setCoordinate(0, new Point3f (-0.3f, 0.5f, 0.0f));
triangle.setCoordinate(1, new Point3f (-0.65f, -0.6f, 0.0f));
triangle.setCoordinate(2, new Point3f (0.0f, -0.5f, 0.0f));
triangle.setColor(0, new Color3f(1.0f, 0.0f, 0.0f));
triangle.setColor(1, new Color3f(1.0f, 1.0f, 0.0f));
triangle.setColor(2, new Color3f(1.0f, 0.0f, 1.0f));
TransformGroup tg = new TransformGroup();
tg.addChild(new Shape3D(triangle));
Transform3D rotation = new Transform3D();
rotation.rotY(0.9);
tg.setTransform(rotation);
objRoot.addChild(tg);
// Compilamos para optimizar
objRoot.compile();
return objRoot;
}
public BasicTransform() {
}
public void init() {
setLayout(new BorderLayout());
GraphicsConfiguration config =
SimpleUniverse.getPreferredConfiguration();
Canvas3D c = new Canvas3D(config);
add("Center", c);
// Crear una escena y atacarla al universo virtual
BranchGroup scene = createSceneGraph();

u = new SimpleUniverse(c);
// Mueve el punto de vista un poco atrs para ver los objetos
u.getViewingPlatform().setNominalViewingTransform();
u.addBranchGraph(scene);
}
public void destroy() {
u.cleanup();
}
public static void main(String[] args) {
new MainFrame(new BasicTransform(), 256, 256);
}
}

3.Interaccin
En los captulos previos hemos hecho varios programas que demuestran las capacidades del API
Java 3D, pero estas capacidades estn bastante limitadas, ya que son estticas. Lo verdaderamente
interesante de los mundos virtuales es la interaccin y animacin que pueden producir. La
interaccin es la respuesta a los eventos producidos por el usuario. La animacin est definida por
los cambios de la escena a lo largo del tiempo sin la interaccin directa del usuario.

3.1 La clase Behavior

En Java 3D la interaccin y la animacin son especificados a travs de los objetos Behavior. La


clase Behavior es una clase abstracta que nos proporcionar una base para acceder a sus
descendientes que nos proporcionarn el cdigo para responder a los cambios en el universo
virtual.
El propsito de los objetos descendientes de Behavior es cambiar el escenario o los objetos en
respuesta a algn tipo de estmulo. Hay muchos tipos de estmulos, como la accin del usuario,
colisiones entre objetos, el transcurso del tiempo o la localizacin de la vista. Cada uno de estos
estmulos har que determinados objetos del escenario se comporten de distinta forma. Por ejemplo,
mientras que la localizacin de la vista puede apenas provocar cambios posibles sobre un
TransformGroup que contenga un BillBoard, si que puede afectar y de manera muy significativa a
los objetos geomtricos en cuanto a su nivel de detalle en la escena.
En los paquetes que tenemos en la distribucin tenemos varias clases que implementan Behavior
y que podremos utilizar en nuestros escenarios sin tener que recurrir a construir nuestras propias
clases Behavior. Algunas de las clases que encontraremos son KeyNavigationBehavior,
MouseBehavior y PickMouseBehavior. Estas clases ya tienen comportamientos definidos que
podremos utilizar para navegar por la escena y el mecanismo para utilizar estas clases es:
1) Preparar el escenario
2) Insertar objetos Behavior en el escenario haciendo referencia a los objetos de cambio
3) Especificar un lmite de accin de los objetos Behavior
4) Establecer las capacidades de escritura y lectura para el destino.
En el siguiente ejemplo utilizaremos el ejemplo del cono y le aadiremos el objeto
KeyNavigationBehavior para poder navegar sobre nuestro universo virtual. Si ejecutamos el
ejemplo podremos navegar con las teclas de direccin del teclado.

package es.udc.fi.gc;

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.behaviors.keyboard.KeyNavigatorBehavior;
import com.sun.j3d.utils.geometry.Cone;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.Point3d;
public class MovingCone extends Applet {

private SimpleUniverse u = null;


public BranchGroup createSceneGraph() {
// Crear la raiz de la rama del grfico
BranchGroup objRoot = new BranchGroup();
// Crear un objeto Shape3D y aadirlo a la escena.
Appearance apariencia = new Appearance();
apariencia.setColoringAttributes(new ColoringAttributes(0.3f, 1.0f,1.0f,
ColoringAttributes.SHADE_FLAT));
Node node = new Cone(0.5f,0.3f,apariencia);
objRoot.addChild(node);
// Cogemos el TG del universo virtual, ya que queremos que los
// cambios afecten a toda la esdena
TransformGroup tg = u.getViewingPlatform().getViewPlatformTransform();
// Le decimos a nuestro Behavior que aplique los cambios al TG
KeyNavigatorBehavior keyNavBeh = new KeyNavigatorBehavior(tg);
// Establecemos los lmites
keyNavBeh.setSchedulingBounds(new BoundingSphere (new Point3d(),100));
// Aadimos el Behavior a la escena
objRoot.addChild(keyNavBeh);

// Compilamos para optimizar


objRoot.compile();
return objRoot;
}
public MovingCone() {
}
public void init() {
setLayout(new BorderLayout());
GraphicsConfiguration config =
SimpleUniverse.getPreferredConfiguration();

Canvas3D c = new Canvas3D(config);


add("Center", c);
// Crear una escena y atacarla al universo virtual
u = new SimpleUniverse(c);
BranchGroup scene = createSceneGraph();
// Mueve el punto de vista un poco atrs para ver los objetos
u.getViewingPlatform().setNominalViewingTransform();
u.addBranchGraph(scene);
}
public void destroy() {
u.cleanup();
}
public static void main(String[] args) {
new MainFrame(new MovingCone(), 256, 256);
}
}

3.2 Construyendo nuestra propia clase Behavior


Para construir nuestra propia clase de respuesta de interaccin debemos de implementar a la clase
Behavior, y especficamente a los mtodos abstractos initialize () y processStimulus(). En el
constructor de nuestra clase debemos requerir como parmetro un TransformGroup sobre el que
vamos a realizar nuestras respuestas a los estmulos, especificar el evento que lanzar nuestras
modificaciones y reinstalarlo. El siguiente trozo de cdigo muestra un ejemplo en el cual cada vez
que presionamos una tecla rotaremos el TransformGroup.
package es.udc.fi.gc;
import java.awt.event.KeyEvent;
import java.util.Enumeration;
import javax.media.j3d.Behavior;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.WakeupOnAWTEvent;
public class KeyRotationBehavior extends Behavior {
private TransformGroup targetTG;
private Transform3D rotation = new Transform3D();

private double angle = 0.0;


// Constructor con TransformGroup como parmetro
public KeyRotationBehavior(TransformGroup tg) {
this.targetTG = tg;
}
// Establecemos el evento ante el cual desencadenaremos
// nuestras respuestas.
// En este caso, el evento ser la presin de una tecla.
public void initialize() {
this.wakeupOn(new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED));
}
// Realizamos la transformacin del TransformGroup como respuesta
// al estmulo y volvemos a establecer el estmulo ante el que
// reaccionaremos.
public void processStimulus(Enumeration arg0) {
angle +=0.1;
rotation.rotX(angle);
targetTG.setTransform(rotation);
this.wakeupOn(new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED));
}
}

4.Animacin
Ciertos objetos pueden cambiar independientemente de las acciones del usuario, por ejemplo las
manecillas de un reloj deberan de moverse sin tener que depender del estmulo del usuario. Las
manecillas de un reloj son un ejemplo de animacin. En este manual consideramos una animacin
como los cambios producidos en nuestra escena debido al transcurrir del tiempo y sin necesitar la
interaccin del usuario.
Como sucede con las interacciones, las animaciones son implementadas usando los objetos
Behavior, y como hemos visto con la interaccin, podemos describir nuestros propios descendientes
de Behavior o utilizar aquellos que ya vienen definidos en la distribucin.
Una de las clases de animacin que veremos es la clase Interpolator. Un objeto Interpolator, junto
con un objeto Alpha, manipula un objeto visual de la escena para conseguir una animacin basada
en el tiempo.
Otro conjunto de clases de animacin de objetos visuales son los BillBoard y LOD (Nivel de
detalle) que no responden al paso del tiempo sino al cambio de punto de vista del usuario.

4.1 Objetos Interpolator y Alpha

Un objeto Alpha produce una valor entre 0.0 y 1.0 incluidos que cambian con el tiempo y que
generan una onda y que marcarn los tiempos de nuestra animacin y las veces que se repetir la
onda. La forma de las fases de las que consta nuestra onda son todas parametrizables a travs del
objeto Alpha y podremos alterarlas para que, si es lo que deseamos, la onda slo est formado por
una fase.
Ahora que ya sabemos qu es un objeto Alpha y para que sirve, veremos como se integra con el
objeto Interpolator. Para conseguir animacin con el objeto Interpolator deberemos de seguir los
siguientes pasos:

crear un objeto al que aplicar la animacin con las capacidades apropiadas

crear un objeto Alpha

crear el objeto Interpolator haciendo referencia al objeto Alpha y al objeto destino

aadir los lmites para el objeto Interpolator

aadir el objeto Interpolator a nuestra escena

En el primer ejemplo que mostramos en este tutorial vimos un ejemplo de la aplicacin de los
objetos Interpolator y Alpha. El cdigo era muy parecido al siguiente, con la salvedad de que hemos
cambiado el eje de rotacin al eje X:

package es.udc.fi.gc;

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
public class RotColorCube extends Applet {
private SimpleUniverse u = null;
public BranchGroup createSceneGraph() {
// Crear la raiz de la rama del grfico
BranchGroup objRoot = new BranchGroup();
// Crear el nodo TransformGroup y engancharlo a la raz
// Habilitar la capacidad TRANSFORM_WRITE para que se pueda modificar
// en tiempo de ejecucin.
TransformGroup objSpin = new TransformGroup();
objSpin.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
// Creamos un objeto Alpha rota indefinidamente y con un
// periodo de 1 minuto
Alpha alpha = new Alpha(-1, 6000);

// Creamos un objeto Interpolator que gire sobre el eje X


Transform3D axisX = new Transform3D();
axisX.setRotation(new Matrix3f(0.0f,1.0f,0.0f,1.0f,0.0f,0.0f,0.0f,0.0f,1.0f));
RotationInterpolator rotX = new RotationInterpolator(alpha, objSpin,axisX,-10,4);
rotX.setSchedulingBounds(new BoundingSphere(new Point3d(),100));
// Construimos nuestra escena
objRoot.addChild(objSpin);
objSpin.addChild(new ColorCube(0.6));
objRoot.addChild(rotX);
// Compilamos para optimizar
objRoot.compile();
return objRoot;
}
public RotColorCube() {
}
public void init() {
setLayout(new BorderLayout());
GraphicsConfiguration config =
SimpleUniverse.getPreferredConfiguration();
Canvas3D c = new Canvas3D(config);
add("Center", c);
// Crear una escena y atacarla al universo virtual
BranchGroup scene = createSceneGraph();
u = new SimpleUniverse(c);
// Mueve el punto de vista un poco atrs para ver los objetos
u.getViewingPlatform().setNominalViewingTransform();
u.addBranchGraph(scene);
}
public void destroy() {
u.cleanup();
}
public static void main(String[] args) {

new MainFrame(new RotColorCube(), 256, 256);


}
}

Adems del RotationInterpolator tambin podremos utilizar los interpoladores ya definidos como
ColorInterpolator, PathInterpolator, PositionInterpolator, ScaleInterpolator y
TransparencyInterpolator, cuyo funcionamiento es muy similar al ya descrito RotationInterpolator.

4.2 Clase BillBoard


El trmino billboard usado en el contexto de los grficos en computacin se refiere a la tcnica
de rotar automticamente un objeto visual plano para que se encuentre siempre mirando al visor. La
principal motivacin para utilizar el billboard es la de disminuir los costes de computacin de
objetos complejos. El ejemplo clsico de utilizacin de billboards es en la representacin de rboles
de un paisaje.

4.2.1 Usando un billboard.

El comportamiento billboard funciona bien para los rboles porque estos parecen bsicamente
los mismos cuando son vistos desde el frente, atrs o desde cualquier otro ngulo. Como un
billboard hace que un objeto visual parezca el mismo desde todos los ngulos de vista sern
apropiados para representar objetos 3D que son geomtricamente simtricos sobre el eje Y.
Usar un objeto billboard es muy similar a un objeto interpolator, excepto que no existe un objeto
Alpha que controle la animacin. La animacin del billboard se controla por la posicin relativa al
visor en el mundo virtual. Los pasos para usar un Billboard son:
1. Crear un TransformGroup con ALLOW_TRANSFORM_WRITE de destino
2. Crear un objeto BillBoard haciendo referencia al TransformGroup de destino.
3. Suministrar unos lmites para el objeto BillBoard
4. Construir el escenario.
Un cdigo de ejemplo mostrando su funcionamiento es el siguiente:
public BranchGroup createSceneGraph(SimpleUniverse u) {
BranchGroup objRoot = new BranchGroup();
Vector3f translate = new Vector3f();
Transform3D T3D = new Transform3D();
TransformGroup TGT = new TransformGroup();
TransformGroup TGR = new TransformGroup();
Billboard billboard = null;
BoundingSphere bSphere = new BoundingSphere();

translate.set(new Point3f(1.0f, 1.0f, 0.0f));


T3D.setTranslation(translate);
TGT.setTransform(T3D);
// Establecemos el billboard
TGR.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
billboard = new Billboard(TGR);
billboard.setSchedulingBounds(bSphere);
// Construimos la escena
objRoot.addChild(TGT);
objRoot.addChild(billboard);
TGT.addChild(TGR);
TGR.addChild(crearArboles());
return objRoot;
}

4.3 Animaciones LOD


El trmino LOD se utiliza para nombrar una tcnica que vara la cantidad de detalles de un objeto
virtual basndose en otro valor del mundo virtual. Lo normal es cambiar el LOD basndonos en la
distancia al visor. Tal y como la distancia entre el visor y el objeto aumenta iremos disminuyendo el
nivel de detalle del objeto visual, ganando as tiempo de procesamiento para otros objetos. Otras
aplicaciones en las que se suele utilizar es cuando queremos mantener una velocidad de frames
constante, sin importar la velocidad a la que cambie el mundo virtual.
Cada objeto LOD tiene uno o ms objetos Switch como destino, que ir cambiando dependiendo
del valor parmetro que hayamos fijado. En el caso de un objeto DistanceLOD, se cambiar
conforme a la distancia al objeto. Las distancias se especifican con un array que empieza con la
distancia mxima del primer hijo del Switch que ser usado. Cuando la distancia desde el objeto
DistanceLOD al visor es mayor que el primer lmite, se cambiar al segundo hijo del Switch y as
consecutivamente.
Los pasos a seguir par usar un objeto DistanceLOD son:
1. Crear objetos Switch con la capacidad ALLOW_SWITCH_WRITE
2. Crear una lista de limites de distancias para el objeto DistanceLOD
3. Crear un objeto DistanceLOD usando la lista de lmites
4. Establecer el switch de destino para el objeto DistanceLOD
5. Suministrar los lmites para el objeto DistanceLOD
6. construir la escena

En el siguiente ejemplo crearemos varias esferas de distinto nivel de detalle y distintos colores
que irn apareciendo dependiendo de la distancia a la que se encuentren del visor.

El cdigo de este ejemplo es el siguiente:


package es.udc.fi.gc;
import java.applet.Applet;
import java.awt.*;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.behaviors.vp.*;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
public class LOD extends Applet {
private SimpleUniverse u = null;
public BranchGroup createSceneGraph() {
// Crear la raz
BranchGroup objRoot = new BranchGroup();
// Creamos el TransformGroup y aadimos las capacidades
// que necesitamos
TransformGroup objTrans = new TransformGroup();
objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
objRoot.addChild(objTrans);
// Creamos el switch
Switch sw = new Switch(0);
sw.setCapability(javax.media.j3d.Switch.ALLOW_SWITCH_READ);
sw.setCapability(javax.media.j3d.Switch.ALLOW_SWITCH_WRITE);
// Creamos varios niveles para el switch, con esferas menos
// detalladas y de distintos colores que irn cambiando conforme
// a la distancia del visor
Appearance appearance40 = new Appearance();
appearance40.setColoringAttributes(new ColoringAttributes(0.7f, 1.0f, 0.4f,1));
Sphere sphere40 = new Sphere(0.4f, Sphere.GENERATE_NORMALS, 40);
sphere40.setAppearance(appearance40);

Appearance appearance10 = new Appearance();


appearance10.setColoringAttributes(new ColoringAttributes(0.3f, 1.0f, 1.0f,1));
Sphere sphere10 = new Sphere(0.4f, Sphere.GENERATE_NORMALS, 10);
sphere10.setAppearance(appearance10);
Appearance appearance5 = new Appearance();
appearance5.setColoringAttributes(new ColoringAttributes(1.0f, 0.5f, 1.0f,1));
Sphere sphere5 = new Sphere(0.4f, Sphere.GENERATE_NORMALS, 5);
sphere5.setAppearance(appearance5);
Appearance appearance3 = new Appearance();
appearance3.setColoringAttributes(new ColoringAttributes(1.0f, 1.0f, 0.5f,1));
Sphere sphere3 = new Sphere(0.4f, Sphere.GENERATE_NORMALS, 3);
sphere3.setAppearance(appearance3);
sw.addChild(sphere40);
sw.addChild(sphere10);
sw.addChild(sphere5);
sw.addChild(sphere3);
// Aadimos el switch
objTrans.addChild(sw);
BoundingSphere bounds =
new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
// Establecemos el LOD
float[] distances = new float[3];
distances[0] = 5.0f;
distances[1] = 10.0f;
distances[2] = 25.0f;
DistanceLOD lod = new DistanceLOD(distances);
lod.addSwitch(sw);
lod.setSchedulingBounds(bounds);
objTrans.addChild(lod);
// Optimizaciones
objRoot.compile();
return objRoot;
}

public LOD() {
}
public void init() {
setLayout(new BorderLayout());
GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
Canvas3D c = new Canvas3D(config);
add("Center", c);
// Creamos la escena y la atacamos al universo virtual
BranchGroup scene = createSceneGraph();
u = new SimpleUniverse(c);
// aadimos un zoom a la escena
ViewingPlatform viewingPlatform = u.getViewingPlatform();
viewingPlatform.setNominalViewingTransform();

// Aadimos un OrbitBehavior para el Zoom, pero deshabilitamos


// la rotacin y la traslacin
OrbitBehavior orbit = new OrbitBehavior(c,
OrbitBehavior.REVERSE_ZOOM |
OrbitBehavior.DISABLE_ROTATE |
OrbitBehavior.DISABLE_TRANSLATE);
BoundingSphere bounds =
new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
orbit.setSchedulingBounds(bounds);
viewingPlatform.setViewPlatformBehavior(orbit);

u.addBranchGraph(scene);
}
public void destroy() {
u.cleanup();
}
public static void main(String[] args) {
new MainFrame(new LOD(), 512, 512);
}

5. Iluminacin
En el mundo real, en la visualizacin de un objeto no slo se tiene en cuenta el color y la forma
de este, sino que tambin tenemos en cuenta la cantidad y el ngulo de la luz que recibe y las luces y
sombras de los objetos adyacentes. En este captulo presentaremos el modelo de iluminacin en
Java 3D y veremos cmo crear ambientes y sombras para nuestro universo virtual.

5.1 El modelo de iluminacin en Java 3D


Como ya se dijo anteriormente, los colores que recibimos son una combinacin de las
propiedades fsicas del objeto, las caractersticas de las fuentes de luz, la posicin relativa de las
fuentes de luz y los ngulos desde los cuales es visto el objeto. Java 3D usa un modelo de
iluminacin que intenta simular el ambiente real, pero como los clculos de luminosidad son muy
costosos en la especificacin Java 3D se ha propuesto un modelo de iluminacin que no tiene en
cuenta los efectos producidos por el resto de los objetos visuales.
El modelo de iluminacin de Java 3D incorpora tres tipos de reflexiones del mundo real:
ambiente, difusa y enfocada. La reflexin ambiente resulta de las luces de ambiente, que son luces
de poca intensidad pero constantes en todo el escenario. La reflexin difusa es la reflexin normal,
de una fuente de luz sobre un objeto visual. Las reflexiones enfocadas son las reflexiones de mucha
intensidad de una fuente de luz sobre un objeto.
Una limitacin importante en el modelo de iluminacin de Java 3D es que existe un nmero
mximo de fuentes de luces en un escenario. En estos momentos, el lmite est en los 8 focos de
luces, y si intentamos sobrepasar este lmite no podremos observar ms de 8 focos de luz. Aunque
esto depende de la implementacin de la librera, no es recomendable sobrepasar este lmite, ya que
est definido como un valor mnimo por la especificacin y no podremos asegurar el buen
funcionamiento de nuestra aplicacin en otras plataformas si se sobrepasa.

5.2 Receta para los objetos visuales de luz


Para habilitar los objetos visuales de luz en nuestro universo necesitaremos seguir un nmero de
pasos, que como es habitual en este tutorial, los describiremos en forma de receta de cocina. Antes
de nada, mencionaremos un detalles con cierta importancia: las luces no son objetos visibles, con lo
que no intentes ver un foco en el universo virtual.
Los pasos a seguir son:
1. Especificar la fuente de luz
a) Establecer los lmites
b) Aadirlo al escenario
2. Objetos visuales
a) Establecer las normales
b) Establecer las propiedades de los materiales
Si nos olvidamos de cualquiera de estos pasos no podremos observar los efectos de la fuente de

luz. La presencia del objeto Material en el objeto Appearance de un objeto visual es el que nos
habilitar el modelo de luces para este objeto. Sin la presencia de Material el objeto ser coloreado,
pero no ser iluminado por las fuentes de luz.
En la siguiente figura se muestra una luz dbil de ambiente sobre una esfera:

Si a la figura anterior le quitamos la luz de ambiente, la imagen producida ser la siguiente:

Si comparamos las dos imgenes veremos una pequea diferencia de color en las esferas, esta
diferencia ser la provocada por la luz de ambiente.
El cdigo del programa que produjo estas imgenes es el siguiente:
package es.udc.fi.gc;
import java.applet.Applet;

import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.Sphere;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
public class BasicLight extends Applet {
private SimpleUniverse u = null;
public BranchGroup createSceneGraph() {
BranchGroup objRoot = new BranchGroup();
Background background = new Background(0.2f, 0.4f, 0.5f);
background.setApplicationBounds(new BoundingSphere());
Appearance appearance = new Appearance();
appearance.setMaterial(new Material());
// Generamos la esfera con la una apariencia y generamos las normales
Sphere sphere = new Sphere(0.5f, Sphere.GENERATE_NORMALS ,appearance);
AmbientLight light = new AmbientLight();
light.setInfluencingBounds(new BoundingSphere());
objRoot.addChild(light);
objRoot.addChild(sphere);
objRoot.addChild(background);
// Compilamos para optimizar
objRoot.compile();
return objRoot;
}
public BasicLight() {
}
public void init() {
setLayout(new BorderLayout());

GraphicsConfiguration config =
SimpleUniverse.getPreferredConfiguration();
Canvas3D c = new Canvas3D(config);
add("Center", c);
// Crear una escena y atacarla al universo virtual
BranchGroup scene = createSceneGraph();
u = new SimpleUniverse(c);
// Mueve el punto de vista un poco atrs para ver los objetos
u.getViewingPlatform().setNominalViewingTransform();
u.addBranchGraph(scene);
}
public void destroy() {
u.cleanup();
}
public static void main(String[] args) {
new MainFrame(new BasicLight(), 256, 256);
}
}

En el siguiente ejemplo colocaremos una luz direccional y aplicada a variaciones de la misma


figura geomtrica y veremos como la forma de los objetos visuales afecta al tipo de reflexin de la
luz sobre estos.

La nica diferencia en el cdigo de estos dos ejemplos radica en el nmero de vrtices de las
figuras. Mientras que en la figura de la derecha la esfera est construida con 20 vrtices, la figura de
la izquieda est construida con 40. El cdigo de la luz direccional es el siguiente:
Sphere sphere = new Sphere(0.5f, Sphere.GENERATE_NORMALS ,40,appearance);
DirectionalLight light = new DirectionalLight();
light.setInfluencingBounds(new BoundingSphere());
light.setDirection(-1.0f, -1.0f, 0.0f);

5.3 Clases de Luces


El API Java 3D nos suministra cuatro tipo de luces. Cada una de ellas es hija de la clase Light.
La clase Light suministra los mtodos y constantes de las capacidades asociadas para manipular el
estado, color y lmites de un objeto Light. Los tipos de luces y sus efectos son los siguientes:
1. La clase javax.media.j3d.AmbientLight nos suministrar una intensidad de luz igual para
todas las localizaciones y en todas las direcciones.
2. La clase javax.media.j3d.DirectionalLight modela fuentes de luz distantes teniendo un vector
de direccin constante.
3. La clase javax.media.j3d.PointLight especifica una fuente de luz atenuada en un lugar
concreto del espacio que radia luz de forma igual en todas las direcciones.
4. La clase javax.media.j3d.SpotLight es una subclase de PointLight con la adiccin de la
direccin, ngulo de difusin y atributos de concentracin.

5.4 El objeto Material


Las propiedades de un material son especificadas en el objeto Material que est integrado en el
objeto de orden superior Appearance. El objeto Material especifica los colores de ambiente, de
difusin, direccionales y emisivos y el valor de brillo. Cada uno de los tres primeros colores son
usados en el modelo de iluminacin para calcula la reflexin correspondiente. El color emisivo
permite a los objetos visuales brillar en la oscuridad y el valor de brillo slo es usado para calcular
la reflexin direccional. Los mtodos para especificar estos parmetros son setAmbientColor
(Color3f), setDiffuseColor(Color3f), setEmissiveColor(Color3f), setShininess(float) y
setSpecularColor(Color3f).

5.5 Normales
Tal y como se dijo en la seccin 5.2, las normales son un requisito indispensable para la
realizacin de sombreados sobre objetos visuales. La normal de una superficie nos indica cual es la
parte de la superficie que se ver afectada por los efectos de iluminacin. Por esto es tan importante
el definir este parmetro de forma correcta. Para definr correctamente una normal debemos definir
un vector que apunte hacia las fuentes de luz. Para definir las normales cuando creamos objetos
visuales usando las clases Geometry, podremos usar uno de los mtodos setNormal() para
especificar las normales para cada vrtice.

6. Texturas
6.1 Qu es una textura?
La apariencia de los objetos del mundo real depende de su textura. La textura de un objeto es
realmente la geometra de menor detalle de la superficie del objeto. Una textura especifica la
complejidad y densidad de la geometra de la superficie.
Si intentramos modelar una representacin de un objeto real en Java 3D con su textura mediante
las primitivas que hemos visto, el modelo sera imposible de representar debido a su alta
complejidad. Lo que se hace para la simulacin de texturas es la simulacin de estas mediante un
grfico o dibujo, y asignndolo a la forma geomtrica del modelo del objeto visual.

6.2 Construyendo texturas


Para aplicar una textura a un polgono en Java 3D debemos de seguir una serie de pasos que
expresaremos en modo de receta y que son:
1. crear un nodo Appearance
2. cargar el mapa de la textura
3. establecer la textura en el nodo Appearance
4. especificar la localizacin de las imgenes de textura en la geometra

6.2.1 Preparar la imagen de textura

Este paso no requiere programacin alguna y consta de la edicin de nuestra textura en una
herramienta que nos permita la edicin de una imagen. Algo que tenemos que tener en cuenta aqu
es que la imagen debe de tener una dimensin potencia de 2, para optimizar el rendimiento de la
aplicacin, y asegurarnos de que la imagen se graba en un formato de imagen que los cargadores de
Java sean capaces de entender.
6.2.2 Carga de la textura

Ahora que ya hemos preparado nuestro archivo de texturas, podremos cargarlo. Para cargar la
textura utilizaremos una clase de utilidad llamada TextureLoader. Esta clase lo que hace es cargar el
archivo de texturas desde un archivo del sistema de archivos o desde un URL para devolver un
objeto ImageComponent2D. El cdigo para realizar esta operacin es el siguiente:
TextureLoader loader = new TextureLoader(textura.gif, this);
ImageComponent2 image = loader.getImage();

El argumento this en el constructor de TextureLoader es una referencia a un Observador, ya


que para cargar la textura se utiliza el paquete java.awt.image y este paquete carga las clases de
forma asncrona.

6.2.3 Crear el nodo Appearance

Para ser usada como textura la imagen que hemos cargado en el apartado anterior, debemos de
establecerla como textura en un objeto Texture2D. El siguiente cdigo muestra un ejemplo de carga
y asignacin de la textura a un nodo Appearance:
TextureLoader loader = new TextureLoader(textura.jpg, this);
ImageComponent2D image = loader.getImage();
Texture2D texture = new Texture2D();
texture.setImage(0, image);
Appearance appearance = new Apperance();
appearance.setTexture(texture);

6.2.4 Especificando las TextureCoordinates

Ahora lo nico que nos falta es especificar los puntos de colocacin de la textura en la geometra
de nuestro objeto visual. Cada coordenada de la textura especifica un punto de la textura a ser
aplicada a un vrtice. Con la especificacin de algunos de los puntos de la imagen a ser aplicados a
los vrtices de la geometra, la imagen ser acondicionada para que cuadre en ella. Algo que
debemos de tener en cuenta es que las coordenadas de la textura son coordenadas con valores
normalizados. Esto es, cuando establezcamos una coordenada de textura a 1.0f, esto querr
significar que queremos que una de la esquina de la textura estar en un lmite del plano. Vemoslo
con un ejemplo.
En el siguiente trozo de cdigo crearemos un plano y estableceremos en el una textura:
QuadArray plane = new QuadArray(4, GeometryArray.COORDINATES |
GeometryArray.TEXTURE_COORDINATE_2);
Point3f p = new Point3f();
p.set(-1.0f, 1.0f, 0.0f);
plane.setCoordinate(0,p);
p.set(-1.0f, -1.0f, 0.0f);
plane.setCoordinate(1,p);
p.set(1.0f, -1.0f, 0.0f);
plane.setCoordinate(2,p);
p.set(1.0f, 1.0f, 0.0f);
plane.setCoordinate(3,p);
Point2f q = new Point2f();
q.set(0.0f, 1.0f);
plane.setTextureCoordinate(0.q);
q.set(0.0f, 0.0f);
plane.setTextureCoordinate(1,q);
q.set(1.0f, 0.0f);
plane.setTextureCoordinate(2,q);

q.set(1.0f, 1.0f);
plane.setTextureCoordinate(3,q);

En el ltimo ejemplo de este tutorial veremos el cdigo de un programa que carga una textura de
piedra en un cubo que gira. En este ejemplo no ser necesario especificar las coordenadas de la
textura debido a que nuestro objeto visual es cuadrado y encajar perfectamente.

package es.udc.fi.gc;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.image.TextureLoader;
import com.sun.j3d.utils.geometry.Box;
import javax.media.j3d.*;
import javax.vecmath.*;
public class TextureExample extends Applet {
private java.net.URL texImage = null;
private SimpleUniverse u = null;
public BranchGroup createSceneGraph() {
BranchGroup objRoot = new BranchGroup();

TransformGroup objTrans = new TransformGroup();


objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
objRoot.addChild(objTrans);
Appearance app = new Appearance();
Texture tex = new TextureLoader(texImage, this).getTexture();
app.setTexture(tex);
Box textureCube =
new Box(0.4f, 0.4f, 0.4f, Box.GENERATE_TEXTURE_COORDS, app);
objTrans.addChild(textureCube);
Transform3D yAxis = new Transform3D();
Alpha rotationAlpha =
new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, 4000, 0, 0, 0, 0, 0);
RotationInterpolator rotator =
new RotationInterpolator(
rotationAlpha,
objTrans,
yAxis,
0.0f,
(float) Math.PI * 2.0f);
BoundingSphere bounds =
new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
rotator.setSchedulingBounds(bounds);
objTrans.addChild(rotator);
objRoot.compile();
return objRoot;
}
public TextureExample() {
}
public TextureExample(java.net.URL url) {
texImage = url;
}

public void init() {


if (texImage == null) {
// the path to the image for an applet
try {
texImage =new java.net.URL(
getCodeBase().toString() + "../images/stone.jpg");
} catch (java.net.MalformedURLException ex) {
System.out.println(ex.getMessage());
System.exit(1);
}
}
setLayout(new BorderLayout());
GraphicsConfiguration config =
SimpleUniverse.getPreferredConfiguration();
Canvas3D c = new Canvas3D(config);
add("Center", c);
BranchGroup scene = createSceneGraph();
u = new SimpleUniverse(c);
u.getViewingPlatform().setNominalViewingTransform();
u.addBranchGraph(scene);
}
public void destroy() {
u.cleanup();
}
public static void main(String[] args) {
java.net.URL url = null;
if (args.length > 0) {
try {
url = new java.net.URL("file:" + args[0]);
} catch (java.net.MalformedURLException ex) {
System.out.println(ex.getMessage());
System.exit(1);
}
} else {
try {
url = new java.net.URL("file:c:\\stone.jpg");

} catch (java.net.MalformedURLException ex) {


System.out.println(ex.getMessage());
System.exit(1);
}
}
new MainFrame(new TextureExample(url), 256, 256);
}
}

7. Bibliografa

1. Java 3D Specificacion 1.1. (Sun Microsystems)


2. Java 3D Specificacion 1.3.1 (Sun Microsystems)
3. Getting Started with the Java 3D API v1.X (Sun Microsystems)

También podría gustarte