Java 3D (Exercício 2)
Professora: Isabel Harb Manssour
 

O objetivo deste exercício é criar e alterar a aparência de diferentes objetos usando primitivas gráficas, instâncias da classe Geometry e loaders, que permitem importar arquivos obj, 3ds, entre outros.

Inicialmente, será definida a geometria de um modelo em Java 3D através da criação de instâncias das primitivas gráficas: Box, Sphere, Cone e Cylinder. Para testar a criação de primitivas, crie uma nova classe com o nome Primitives e substitua o código que o BlueJ colocou pelo código apresentado abaixo.

/*
 *  @(#)HelloUniverse.java 1.55 02/10/21 13:43:36
 *
 * Copyright (c) 1996-2002 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistribution in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 */

/////////////////////////////////////////////////////////////////////
// Isabel Harb Manssour
// Junho de 2003
// Primitives.java ilustra como criar instâncias de modelos 
// pré-definidos.
// Este código está baseado no demo HelloUniverse.java

import javax.swing.*;
import java.awt.*;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;

public class Primitives extends JFrame {

    /////////////////////////////////////////////////////////////////
    // Atributo da classe Primitives
    //
    private SimpleUniverse universe = null;
    

    /////////////////////////////////////////////////////////////////
    // Construtor da classe HelloUniversePrimitives
    //
    public Primitives() {
        Container container = getContentPane();
        container.setLayout(new BorderLayout());
        GraphicsConfiguration config =
           SimpleUniverse.getPreferredConfiguration();

        Canvas3D canvas = new Canvas3D(config);
        container.add("Center", canvas);

        // Cria um sub-grafo de conteudo
        BranchGroup scene = criaGrafoDeCena();
        universe = new SimpleUniverse(canvas);

        // O código abaixo faz com que a ViewPlatform seja movida
        // um pouco para trás, para que os objetos possam ser
        // visualizados
        universe.getViewingPlatform().setNominalViewingTransform();

	  // Anexa o sub-grafo no universo virtual
        universe.addBranchGraph(scene);
        
        setSize(350,350);
        setVisible(true);
    }
    
    
    /////////////////////////////////////////////////////////////////
    // Método responsável pela criação do grafo de cena (ou sub-grafo)
    //    
    public BranchGroup criaGrafoDeCena() {
        
        // Cria o nodo raiz  
        BranchGroup objRaiz = new BranchGroup();

        // Cria o nodo TransformGroup e permite que ele possa
        // ser alterado em tempo de execução (TRANSFORM_WRITE).
        // Depois, adiciona-o na raiz do grafo de cena.
        TransformGroup objTrans = new TransformGroup();
        objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        objRaiz.addChild(objTrans);

	  // Cria um "bounds" 
	  BoundingSphere bounds =
	       new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
	
        Appearance app = new Appearance();
        ColoringAttributes ca = new ColoringAttributes();
        ca.setColor(new Color3f(0.0f, 1.0f, 0.0f));
        app.setColoringAttributes(ca);      
        
        com.sun.j3d.utils.geometry.Box cubo = 
           new com.sun.j3d.utils.geometry.Box(0.2f, 0.2f, 0.2f, app); 

        cubo.setAppearance(app);
        
        objTrans.addChild(cubo);
    
        // Cria um novo objeto Behaviour que irá executar as 
        // operações desejadas no "transform" especificado  
        // e adiciona-o no grafo.
        Transform3D trans = new Transform3D();
        trans.rotZ(Math.toRadians(60));
        
        Alpha rotacaoAlpha = new Alpha(-1, 4000);
        
        RotationInterpolator rotator =
               new RotationInterpolator(rotacaoAlpha, objTrans, trans,
                                         0.0f, (float) Math.PI*2.0f);               
        rotator.setSchedulingBounds(bounds);
    
        objRaiz.addChild(rotator);    
    
        // Para o Java 3D realizar otimizações no grafo de cena
        objRaiz.compile();

        return objRaiz;
    }


    /////////////////////////////////////////////////////////////////
    // Método principal que permite executar a aplicação
    //
    public static void main(String[] args) 
    {
        Primitives h = new Primitives();
    }

}

Ao executar o código acima é aberta uma janela que contém um cubo verde que gira. Entretanto, não é possível verificar que é exatamente um "cubo", certo? Isto ocorre porque todas as faces estão com a mesma cor. Para se ter a "sensação de 3D", é necessário alterar a cor ao longo da superfície do objeto considerando a existência de uma fonte de luz. Neste caso, ao invés de se definir apenas uma cor para a aparência do objeto, é necessário definir um "material", que descreve as propriedades da sua superfície (se é opaca, brilhosa, etc.). Portanto, substitua o trecho de código:

    ColoringAttributes ca = new ColoringAttributes();
    ca.setColor(new Color3f(0.0f, 1.0f, 0.0f));
    app.setColoringAttributes(ca);
por
    //Parâmetros: Color3f ambientColor, Color3f emissiveColor, 
    //            Color3f diffuseColor, Color3f specularColor, 
    //            float shininess
    Material material=new Material(new Color3f(0.8f,0.8f,0.1f),new Color3f(0.0f,0.0f,0.0f), 
                                   new Color3f(0.8f,0.8f,0.1f),new Color3f(1.0f,1.0f,1.0f), 
                                   100.0f); 
    app.setMaterial(material);
O que aparece quando o programa é executado? Nada?

Correto!!! Pois, se estamos definindo um material que brilha de acordo com a fonte de luz, se não houver uma fonte, não será possível ver o objeto! Então, acrescente o seguinte trecho de código antes da criação do objeto Appearance app:

    // Especifica as luzes do "ambiente"
    Color3f corLuz = new Color3f(0.9f, 0.9f, 0.9f);
    Vector3f direcaoLuz  = new Vector3f(-1.0f, -1.0f, -1.0f);
    Color3f corAmb = new Color3f(0.2f, 0.2f, 0.2f);

    AmbientLight luzAmb = new AmbientLight(corAmb);
    luzAmb.setInfluencingBounds(bounds);
    DirectionalLight luzDir = new DirectionalLight(corLuz, direcaoLuz);
    luzDir.setInfluencingBounds(bounds);
    objRaiz.addChild(luzAmb);
    objRaiz.addChild(luzDir);

Agora experimente trocar os valores dos parâmetros do objeto Material para criar diferentes "aparências" para o objeto, considerando que: ambientColor é a cor ambiente refletida da superfície do material; emissiveColor é a cor da luz que o material emite; diffuseColor é cor do material quando iluminado; specularColor é a cor especular do material; e shininess é a concentração do brilho do material que varia entre 1 e 128, sendo 128 o brilho máximo.

Para verificar como se criam outras primitivas, substitua no programa o seguinte trecho de código:

    com.sun.j3d.utils.geometry.Box cubo = 
                         new com.sun.j3d.utils.geometry.Box(0.2f, 0.2f, 0.2f, app); 
    cubo.setAppearance(app);

pelos trechos de código colocados abaixo, UM DE CADA VEZ!!! A cada alteração, compile e execute o programa para verificar o resultado! Para saber mais informações sobre os construtores destes objetos consulte os slides do módulo 2 ou a API do Java 3D.

    // Opção 1: cria uma esfera
    Sphere esfera = new Sphere(0.6f);
    esfera.setAppearance(app);   

    // Opção 2: cria um cilindro
    Cylinder cilindro = new Cylinder(0.5f, 0.8f, 1, 20, 10, app);

    // Opção 2: cria um cone
    Cone cone = new Cone(0.4f, 0.8f);
    cone.setAppearance(app);

Acrescente agora um fundo colorido na imagem. Copie o trecho de código abaixo, logo após a criação do objeto BoundingSphere bounds.

    // Especifica um background azul e adiciona-o no grafo
    Color3f bgColor = new Color3f(0.1f, 0.1f, 0.7f);
    Background bg = new Background(bgColor);
    bg.setApplicationBounds(bounds);
    objRaiz.addChild(bg);

Outra maneira de definir a geometria de um modelo é através da criação de instâncias das subclasses da classe abstrata Geometry. Para ver um exemplo de como criar geometrias desta forma, crie uma nova classe chamada GeometryExample e substitua o código que o BlueJ colocou pelo código apresentado abaixo. Neste exemplo é possível utilizar o mouse para interagir da seguinte maneira:

  • Rotação: arrastar o mouse com o botão esquerdo pressionado;
  • Translação: arrastar o mouse com o botão direito pressionado;
  • Zoom: arrastar o mouse com o botão do meio pressionado (ou alt+botão esquerdo).

/*
 *  @(#)HelloUniverse.java 1.55 02/10/21 13:43:36
 *
 * Copyright (c) 1996-2002 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistribution in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 */

///////////////////////////////////////////////////////////////////////////
// Isabel Harb Manssour
// Outubro de 2003
// GeometryExample.java ilustra como criar geometria.
// Este código está baseado no demo HelloUniverse.java

import javax.swing.*;
import java.awt.*;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.behaviors.vp.*;
import javax.media.j3d.*;
import javax.vecmath.*;

public class GeometryExample extends JFrame
{
    ///////////////////////////////////////////////////////////////////////
    // Atributo da classe GeometryExample
    //
    private SimpleUniverse universe = null;
    

    ///////////////////////////////////////////////////////////////////////
    // Construtor da classe GeometryExample
    //
    public GeometryExample() 
    {
        Container container = getContentPane();
        container.setLayout(new BorderLayout());
        GraphicsConfiguration config =
           SimpleUniverse.getPreferredConfiguration();

        Canvas3D canvas = new Canvas3D(config);
        container.add("Center", canvas);

        // Cria um sub-grafo de conteúdo
        BranchGroup scene = criaGrafoDeCena();
       
        universe = new SimpleUniverse(canvas);
     
        // O código abaixo faz com que a ViewPlatform seja movida
        // um pouco para trás, para que os objetos possam ser
        // visualizados
        ViewingPlatform viewingPlatform = universe.getViewingPlatform();
        viewingPlatform.setNominalViewingTransform();
        
        // O código abaixo altera o field-of-view para 
        // permitir a visualização de todos objetos
        View view = universe.getViewer().getView();
        view.setFieldOfView(view.getFieldOfView()*1.4);

        // Adiciona "mouse behaviors" à "viewingPlatform" 
        // (equivale a trocar a posição do "observador virtual")
        OrbitBehavior orbit = 
                      new OrbitBehavior(canvas, OrbitBehavior.REVERSE_ALL);
        BoundingSphere bounds = 
                      new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
        orbit.setSchedulingBounds(bounds);
        viewingPlatform.setViewPlatformBehavior(orbit);

        // Anexa o sub-grafo no universo virtual
        universe.addBranchGraph(scene);
        
        setSize(350,350);
        setVisible(true);
    }
        
    ///////////////////////////////////////////////////////////////////////
    // Método responsável pela criação do grafo de cena (ou sub-grafo)
    //    
    public BranchGroup criaGrafoDeCena() 
    {        
        // Cria o nodo raiz 
        BranchGroup objRaiz = new BranchGroup();
        objRaiz.setCapability(BranchGroup.ALLOW_BOUNDS_READ);
        
        // Cria o nodo TransformGroup e permite que ele possa
        // ser alterado em tempo de execução (TRANSFORM_WRITE).
        // Depois, adiciona-o na raiz do grafo de cena.
        TransformGroup objTrans = new TransformGroup();
        objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        objRaiz.addChild(objTrans);

        // Cria um "bounds" para o background 
        BoundingSphere bounds =
           new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);

        // Especifica um background azul e adiciona-o no grafo
        Color3f bgColor = new Color3f(0.1f, 0.1f, 0.7f);
        Background bg = new Background(bgColor);
        bg.setApplicationBounds(bounds);
        objRaiz.addChild(bg);

        // Especifica as luzes do "ambiente" (ambiente e direcional)
        Color3f corAmb = new Color3f(0.2f, 0.2f, 0.2f);
        AmbientLight luzAmb = new AmbientLight(corAmb);
        luzAmb.setInfluencingBounds(bounds);
        objRaiz.addChild(luzAmb);
          
        Color3f corLuz = new Color3f(0.9f, 0.9f, 0.9f);        
        Vector3f direcaoLuz1  = new Vector3f(-1.0f, -1.0f, -1.0f);
        Vector3f direcaoLuz2  = new Vector3f(1.0f, -1.0f, -1.0f);
        DirectionalLight luzDir1 = new DirectionalLight(corLuz,direcaoLuz1);
        DirectionalLight luzDir2 = new DirectionalLight(corLuz,direcaoLuz2);
        luzDir1.setInfluencingBounds(bounds);
        luzDir2.setInfluencingBounds(bounds);
        objRaiz.addChild(luzDir1);          
        objRaiz.addChild(luzDir2);

        // Especifica a aparência do material
        Appearance app = new Appearance();
        Material material = new Material(new Color3f(0.7f,0.1f,0.7f), 
                                         new Color3f(0.0f,0.0f,0.0f), 
                                         new Color3f(0.7f,0.1f,0.7f), 
                                         new Color3f(1.0f,1.0f,1.0f), 60.0f);
        app.setMaterial(material);

        Shape3D s3d = new Shape3D();
        s3d.setAppearance (app);
        s3d.setGeometry (cubeGeometry());
        objTrans.addChild(s3d);          
  
        // Cria outro nodo TransformGroup node e permite que ele possa
        // ser alterado em tempo de execução (TRANSFORM_WRITE).
        // Depois, adiciona-o na raiz do grafo.
        TransformGroup textTrans = new TransformGroup();
        textTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        objRaiz.addChild(textTrans);
        
        // Cria um novo objeto que irá aplicar as transformações
        // geométricas sobre texto e o adicina no grafo.
        Transform3D trans = new Transform3D();
        Transform3D t1 = new Transform3D();
        
        t1.rotX(Math.toRadians(-10.0));
        trans.mul(t1);
        trans.setScale(0.3);
        trans.setTranslation(new Vector3d(-0.5,0.7,0.0));
        
        textTrans.setTransform(trans);      
 
        Font3D font3d = new Font3D(new Font("Helvetica", Font.PLAIN, 1),
                                   new FontExtrusion());
        Text3D textGeom = new Text3D(font3d, new String("Geometria!"),
                                     new Point3f(-1.0f, 0.0f, 0.0f));
        Shape3D textShape = new Shape3D(textGeom);
        textShape.setAppearance(app);

        textTrans.addChild(textShape); 
 
        // Para o Java 3D realizar otimizações no grafo de cena
        objRaiz.compile();

        return objRaiz;
    }

    ///////////////////////////////////////////////////////////////////////
    // Método responsável pela criação de um cubo usando GeometryArray
    //   
    private Geometry cubeGeometry() 
    {
        GeometryInfo gi = new GeometryInfo(GeometryInfo.QUAD_ARRAY);
        Point3f[] pts = new Point3f[8];
        pts[0] = new Point3f(-0.5f, 0.5f, 0.5f);
        pts[1] = new Point3f(0.5f, 0.5f, 0.5f);        
        pts[2] = new Point3f(0.5f, -0.5f, 0.5f);
        pts[3] = new Point3f(-0.5f, -0.5f, 0.5f);
        pts[4] = new Point3f(-0.5f, 0.5f, -0.5f);
        pts[5] = new Point3f(0.5f, 0.5f, -0.5f);
        pts[6] = new Point3f(0.5f, -0.5f, -0.5f);
        pts[7] = new Point3f(-0.5f, -0.5f, -0.5f);
        int[] indices = {
            0,4,7,3, // left face   
            6,2,3,7, // bottom face 
            4,5,6,7, // back face   
            5,1,2,6, // right face  
            5,4,0,1, // top face    
            1,0,3,2  // front face 
        };
        gi.setCoordinates(pts);
        gi.setCoordinateIndices(indices);
        NormalGenerator ng = new NormalGenerator();
        // Passar 100 como parâmetro para a função abaixo, faz com que
        // as "dobras" (união das faces) fique mais suave do que se fosse  
        // passado um valor mais baixo
        ng.setCreaseAngle( (float) Math.toRadians(100) );
        ng.generateNormals(gi);
        GeometryArray cube = gi.getGeometryArray();
        return cube;
    } 

    
    ///////////////////////////////////////////////////////////////////////
    // Método principal que permite executar a aplicação
    //
    public static void main(String[] args) 
    {
        GeometryExample g = new GeometryExample();
    }
    
}

Analise o método cubeGeometry e experimente trocar o comando ng.setCreaseAngle( (float) Math.toRadians(100) ); por ng.setCreaseAngle( (float) Math.toRadians(45) ); e executar o programa novamente.

Finalmente, para ver como pode ser carregado um arquivo .obj criado por uma ferramenta de modelagem, tal como o 3D Studio, crie uma nova classe com o nome LoaderExample e substitua o código que o BlueJ colocou pelo código apresentado abaixo. Experimente trocar o nome do arquivo "galleon.obj" por "sofa.obj", "computer.obj" ou "Teapot.obj"(certifique-se que estes arquivos disponíveis em "arquivos.zip" estão na mesma pasta que a sua aplicação). Experimente também trocar a cor da fonte de luz para ver o resultado.

/*
 *  @(#)HelloUniverse.java 1.55 02/10/21 13:43:36
 *
 * Copyright (c) 1996-2002 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistribution in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 */

///////////////////////////////////////////////////////////////////////////
// Isabel Harb Manssour
// Junho de 2003
// LoaderExample.java ilustra como criar instâncias de modelos
// pré-definidos.
// Este código está baseado no demo HelloUniverse.java

import java.applet.Applet;
import javax.swing.*;
import java.net.URL;
import java.awt.*;
import java.io.*;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.behaviors.vp.*;
import com.sun.j3d.loaders.objectfile.ObjectFile; 
import com.sun.j3d.loaders.ParsingErrorException; 
import com.sun.j3d.loaders.IncorrectFormatException; 
import com.sun.j3d.loaders.Scene;
import javax.media.j3d.*;
import javax.vecmath.*;

public class LoaderExample extends Applet {

    ///////////////////////////////////////////////////////////////////////
    // Atributo da classe HelloUniverseBehavior
    //
    private SimpleUniverse universe = null;
    

    ///////////////////////////////////////////////////////////////////////
    // Método init da applet
    //
    public void init() {
        setLayout(new BorderLayout());
        GraphicsConfiguration config =
           SimpleUniverse.getPreferredConfiguration();

        Canvas3D canvas = new Canvas3D(config);
        add("Center", canvas);

        // Cria um sub-grafo de conteúdo
        BranchGroup scene = criaGrafoDeCena();
        universe = new SimpleUniverse(canvas);

        // O código abaixo faz com que a ViewPlatform seja movida
        // um pouco para trás, para que os objetos possam ser
        // visualizados
        ViewingPlatform viewingPlatform = universe.getViewingPlatform();
        viewingPlatform.setNominalViewingTransform();
        
        // O código abaixo altera o field-of-view para 
        // permitir a visualização de todos objetos
        View view = universe.getViewer().getView();
        view.setFieldOfView(view.getFieldOfView()*1.4);
        
        // Adiciona "mouse behaviors" à "viewingPlatform" 
        // (equivale a trocar a posição do "observador virtual")
        OrbitBehavior orbit = 
                       new OrbitBehavior(canvas, OrbitBehavior.REVERSE_ALL);
        BoundingSphere bounds = 
                       new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
        orbit.setSchedulingBounds(bounds);
        viewingPlatform.setViewPlatformBehavior(orbit);
     
        // Anexa o sub-grafo no universo virtual
        universe.addBranchGraph(scene);
        
        setSize(350,350);
        setVisible(true);
    }
    
    
    ///////////////////////////////////////////////////////////////////////
    // Método responsável pela criação do grafo de cena (ou sub-grafo)
    //    
    public BranchGroup criaGrafoDeCena() {
        
        // Cria o nodo raiz 
        BranchGroup objRaiz = new BranchGroup();

        // Cria o nodo TransformGroup e permite que ele possa
        // ser alterado em tempo de execução (TRANSFORM_WRITE).
        // Depois, adiciona-o na raiz do grafo de cena.
        TransformGroup objTrans = new TransformGroup();
        objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        objRaiz.addChild(objTrans);

        // Cria um "bounds" para o background 
        BoundingSphere bounds =
           new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);

        // Especifica um background azul e adiciona-o no grafo
        Color3f bgColor = new Color3f(0.2f, 0.2f, 0.7f);
        Background bg = new Background(bgColor);
        bg.setApplicationBounds(bounds);
        objRaiz.addChild(bg);

        // Especifica as luzes do "ambiente"
        
        // Luz Ambiente
        Color3f corAmb = new Color3f(0.2f, 0.2f, 0.2f);
        AmbientLight luzAmb = new AmbientLight(corAmb);
        luzAmb.setInfluencingBounds(bounds);
        objRaiz.addChild(luzAmb);        
        
        // Luz Pontual (Color3f c, Point3f position, Point3f attenuation)
        Color3f corLuz = new Color3f(0.9f, 0.9f, 0.9f);        
        Point3f posicaoLuz1   = new Point3f(0.6f, 2.0f, 0.2f); 
        Point3f posicaoLuz2   = new Point3f(-0.6f, 2.0f, -0.2f); 
        Point3f atenuacaoLuz  = new Point3f(0.1f, 0.1f, 0.1f);       
        PointLight luzPont = new PointLight(corLuz, posicaoLuz1, atenuacaoLuz);
        luzPont.setInfluencingBounds(bounds);
        objRaiz.addChild(luzPont);              
        PointLight luzPont2 = new PointLight(corLuz, posicaoLuz2, atenuacaoLuz);
        luzPont2.setInfluencingBounds(bounds);
        objRaiz.addChild(luzPont2);  
        
        ObjectFile f =
                  new ObjectFile(ObjectFile.RESIZE,(float)(60.0*Math.PI/180.0));        
        Scene s = null;
        
        try {
            s=f.load(new java.net.URL(getCodeBase().toString() + "./galleon.obj")); 
        }
        catch (FileNotFoundException e) {
            System.err.println(e);
            System.exit(1);
        }
        catch (ParsingErrorException e) {
            System.err.println(e);
            System.exit(1);
        }
        catch (IncorrectFormatException e) {
            System.err.println(e);
            System.exit(1);
        }
        catch (java.net.MalformedURLException ex) {
            System.out.println(ex.getMessage());
            System.exit(1);
        }         

        objRaiz.addChild(s.getSceneGroup());
    
        // Para o Java 3D realizar otimizações no grafo de cena
        objRaiz.compile();

        return objRaiz;
    }
}

 ../Imagens/emban15.png(1469 bytes)

../Imagens/E-MAIL.JPG (3237 bytes) Comentários, dúvidas, sugestões, envie um mail para [email protected]

../Imagens/emban15.png(1469 bytes)

[Homepage Java 3D]  [Homepage Isabel H. Manssour]

Última alteração em 11 de outubro de 2003.