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;
}
}
|
Comentários, dúvidas, sugestões, envie um mail para [email protected]
|