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

O objetivo deste exercício é verificar como trabalhar com interação e animação em Java 3D.

O próximo exemplo mostra como é possível interagir na cena 3D usando o mouse. Neste caso, o objeto fica parado e quem se movimenta é o "observador virtual". Portanto, crie uma nova classe com o nome BehaviorExample e substitua o código que o BlueJ colocou pelo código apresentado abaixo. Utilize 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
// Junho de 2003
// BehaviorExample.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 com.sun.j3d.utils.behaviors.vp.*;
import javax.media.j3d.*;
import javax.vecmath.*;

public class BehaviorExample extends JFrame {

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

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

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

        // Cria um grafo de cena
        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();
        
        // 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);
     
        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 nó 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.1f, 0.1f, 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 Direcional
        Color3f corLuz = new Color3f(0.9f, 0.9f, 0.9f);
        Vector3f direcaoLuz  = new Vector3f(-1.0f, -1.0f, -1.0f);
        DirectionalLight luzDir = new DirectionalLight(corLuz, direcaoLuz);
        luzDir.setInfluencingBounds(bounds);
        objRaiz.addChild(luzDir); 
        
        Appearance app = new Appearance();

        //Color3f ambientColor, Color3f emissiveColor, Color3f diffuseColor, 
        //				Color3f specularColor, float shininess
        Material material = new Material(new Color3f(0.8f,0.2f,0.8f), 
						new Color3f(0.0f,0.0f,0.0f), 
						new Color3f(0.8f,0.2f,0.8f), 
						new Color3f(1.0f,1.0f,1.0f), 100.0f); 

        app.setMaterial(material);
        
        Cylinder cilindro = new Cylinder(0.5f, 0.8f, 1, 20, 10, app);
        
        objTrans.addChild(cilindro);  
    
        // 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) 
    {
        BehaviorExample h = new BehaviorExample();
    }
}

A cena parece muito "escura", não? Aproveite para incluir mais de uma fonte de luz. Troque a posição e o tipo da fonte da luz para ver como fica melhor. Use o exemplo abaixo para testar. Inicialmente inclua apenas uma fonte de luz pontual na "posicaoLuz1" (coloque em comentário o trecho de código que inclui a fonte de luz direcional), e depois inclua mais fontes de luz. Experimente trocar a cor e a posição da(s) fonte(s) de luz também.

        // Luz Pontual (Color3f c, Point3f position, Point3f attenuation)
        Color3f corLuz = new Color3f(0.9f, 0.9f, 0.9f);        
        Point3f posicaoLuz1   = new Point3f(0.0f, 1.0f, 0.0f);
        Point3f posicaoLuz2   = new Point3f(0.0f, 0.8f, 0.8f);
        Point3f posicaoLuz3   = new Point3f(0.0f, -0.8f, -0.8f);
        Point3f atenuacaoLuz  = new Point3f(0.1f, 0.1f, 0.1f);        
        PointLight luzPont = new PointLight(corLuz, posicaoLuz2, atenuacaoLuz);
        luzPont.setInfluencingBounds(bounds);
        objRaiz.addChild(luzPont);              
        PointLight luzPont2 = new PointLight(corLuz, posicaoLuz3, atenuacaoLuz);
        luzPont2.setInfluencingBounds(bounds);
        objRaiz.addChild(luzPont2); 

Outro exemplo de interação é apresentado no código a seguir. crie uma nova classe com o nome SimpleBehaviorApp e substitua o código que o BlueJ colocou pelo código apresentado abaixo. Neste exemplo, o cubo é rotacionado sempre que o usuário clica com um botão do mouse. Experimente trocar o parâmetro MouseEvent.MOUSE_CLICKED por KeyEvent.KEY_PRESSED para que cubo seja rotacionado sempre que o usuário pressionar uma tecla ao invés de clicar de com um botão do mouse.

/*
 *  @(#)SimpleBehaviorApp.java 
 *
 * Copyright (c) Sun Microsystems, Inc.
 * 2550 Garcia Avenue, Mountain View, California 94043-1100 U.S.A
 * All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this documentation 
 * for NON-COMMERCIAL purposes and without fee is hereby granted 
 * provided that this copyright notice appears in all copies.
 *
 * Obs: código extraído dos exemplos do tutorial 
 * "Getting Started with the Java 3D™ API - A Tutorial for Beginners
 * http://developer.java.sun.com/developer/onlineTraining/java3d/
 * 
 */

import java.awt.event.*;
import java.util.Enumeration;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;


// SimpleBehaviorApp renders a single, rotated cube.
public class SimpleBehaviorApp extends Applet 
{

 // Atributo
 private SimpleUniverse u = null;

 /////////////////////////////////////////////////////////////
 private class SimpleBehavior extends Behavior{
     private TransformGroup targetTG;
     private Transform3D rotation = new Transform3D();
     private double angle = 0.0;

    // create SimpleBehavior - set TG object of change
    SimpleBehavior(TransformGroup targetTG)
    {
        this.targetTG = targetTG;
    }

    // initialize the Behavior set initial wakeup condition
    // called when behavior becomes live
    public void initialize()
    {
        // set initial wakeup condition
        this.wakeupOn(new WakeupOnAWTEvent(MouseEvent.MOUSE_CLICKED)); 
    }

    // called by Java 3D when appropriate stimulus occurs
    public void processStimulus(Enumeration criteria)
    {
        // do what is necessary in response to stimulus
        angle += 0.1;
        rotation.rotY(angle);
        targetTG.setTransform(rotation);
        this.wakeupOn(new WakeupOnAWTEvent(MouseEvent.MOUSE_CLICKED));
    }
 } // end of class SimpleBehavior
 /////////////////////////////////////////////////////////////


 public BranchGroup createSceneGraph() {
    // Create the root of the branch graph
    BranchGroup objRoot = new BranchGroup();

    TransformGroup objRotate = new TransformGroup();
    objRotate.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    objRoot.addChild(objRotate);
    objRotate.addChild(new ColorCube(0.4));

    SimpleBehavior myRotationBehavior = new SimpleBehavior(objRotate);
    myRotationBehavior.setSchedulingBounds(new BoundingSphere());
    objRoot.addChild(myRotationBehavior);

    // Let Java 3D perform optimizations on this scene graph.
    objRoot.compile();

    return objRoot;
 } // end of CreateSceneGraph method of SimpleBehaviorApp
 
 
 public void init() {
     setLayout(new BorderLayout());
     GraphicsConfiguration config =
           SimpleUniverse.getPreferredConfiguration();
           
     Canvas3D c = new Canvas3D(config);
	 add("Center", c);

	 // Create a simple scene and attach it to the virtual universe
	 BranchGroup scene = createSceneGraph();
	 u = new SimpleUniverse(c);

    // This will move the ViewPlatform back a bit so the
    // objects in the scene can be viewed.
    u.getViewingPlatform().setNominalViewingTransform();

	u.addBranchGraph(scene);
 }
 
}

Já vimos no exercicio1 que uma instância da classe RotationInterpolator define um comportamento e pode ser usada para animar um objeto, pois objetos Interpolator em conjunto com objetos Alpha manipulam alguns parâmetros de um grafo de cena para criar uma animação baseada no tempo. Existem outros "comportamentos" (ou behaviour) que podem ser utilizados, tais como PositionInterpolator (modifica o componente de translação sobre o eixo x do TransformGroup através de uma interpolação linear entre um par de posições especificadas) ou ScaleInterpolator (modifica o componente de escala uniforme do TransformGroup através de uma interpolação linear entre um par de valores de escala especificados). Para verificar como funcionam, substitua na classe HelloUniverse criada anteriormente, o seguinte trecho de código:

    RotationInterpolator rotator = new RotationInterpolator(rotationAlpha, 
                                     objTrans, yAxis, 0.0f, (float) Math.PI*2.0f);

pelos trechos de código colocados abaixo, UM DE CADA VEZ!!! A cada alteração, compile e execute o programa para verificar o resultado!

    // Opção 1
    yAxis.rotZ(Math.toRadians(90));
    RotationInterpolator rotator = new RotationInterpolator(rotationAlpha, 
                                     objTrans, yAxis, 0.0f, (float)Math.PI*2.0f);
   

    // Opção 2
    yAxis.rotX(Math.toRadians(60));
    RotationInterpolator rotator = new RotationInterpolator(rotationAlpha, 
                                     objTrans, yAxis, 0.0f, (float)Math.PI*2.0f);
        

    // Opção 3
    PositionInterpolator rotator = new PositionInterpolator(rotationAlpha, 
                                     objTrans, yAxis, 0.0f, 1.0f);
        

    // Opção 4
    yAxis.rotZ(Math.toRadians(90));
    PositionInterpolator rotator = new PositionInterpolator(rotationAlpha, 
                                     objTrans, yAxis, 0.0f, 1.0f);
        

    // Opção 5
    ScaleInterpolator rotator = new ScaleInterpolator(rotationAlpha, 
                                  objTrans, yAxis, 0.0f, 1.5f);

Agora experimente fazer um movimento de "ir" e "retornar" usando PositionInterpolator. Para isto, substitua o código a seguir:

	Transform3D yAxis = new Transform3D();
	Alpha rotationAlpha = new Alpha(-1, 4000);

	RotationInterpolator rotator =
	    new RotationInterpolator(rotationAlpha, objTrans, yAxis,
				     0.0f, (float) Math.PI*2.0f);

pelo código abaixo.

        Transform3D yAxis = new Transform3D();
        Alpha rotationAlpha = new Alpha(-1, 4000);
        rotationAlpha .setMode(Alpha.INCREASING_ENABLE|Alpha.DECREASING_ENABLE);
        rotationAlpha .setDecreasingAlphaDuration(4000); 

        PositionInterpolator rotator =
             new PositionInterpolator(rotationAlpha , objTrans, yAxis, -1.0f, 1.0f);

 ../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.