|
This Java tip illustrates some of the features of the SimpleUniverse class. It
creates 3 views into a scengraph and associates a ViewerAvatar and
PlatformGeometry with each Viewer object.
The example creates a very simple navigation environment where each Viewer of
the environment can navigate using the keyboard and see the other viewer.
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GraphicsConfigTemplate;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.net.URL;
import java.util.Hashtable;
import javax.media.j3d.AmbientLight;
import javax.media.j3d.Appearance;
import javax.media.j3d.AudioDevice;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.Bounds;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.GraphicsConfigTemplate3D;
import javax.media.j3d.Group;
import javax.media.j3d.ImageComponent2D;
import javax.media.j3d.Locale;
import javax.media.j3d.Material;
import javax.media.j3d.PhysicalBody;
import javax.media.j3d.PhysicalEnvironment;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Texture;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.View;
import javax.media.j3d.ViewPlatform;
import javax.media.j3d.VirtualUniverse;
import javax.vecmath.Color3f;
import javax.vecmath.Point2f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;
import com.sun.j3d.audioengines.javasound.JavaSoundMixer;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.behaviors.keyboard.KeyNavigatorBehavior;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.geometry.Cone;
import com.sun.j3d.utils.geometry.GeometryInfo;
import com.sun.j3d.utils.geometry.NormalGenerator;
import com.sun.j3d.utils.geometry.Primitive;
import com.sun.j3d.utils.image.TextureLoader;
import com.sun.j3d.utils.universe.MultiTransformGroup;
import com.sun.j3d.utils.universe.PlatformGeometry;
import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.universe.Viewer;
import com.sun.j3d.utils.universe.ViewerAvatar;
import com.sun.j3d.utils.universe.ViewingPlatform;
/**
* This example illustrates some of the features of the SimpleUniverse class. It
* creates 3 views into a scengraph and associates a ViewerAvatar and
* PlatformGeometry with each Viewer object.
* <p>
* The example creates a very simple navigation environment where each Viewer of
* the environment can navigate using the keyboard and see the other viewer.
*/
public class PlatformTest extends Applet implements ActionListener {
// size of each Canvas3D
static final int m_kWidth = 256;
static final int m_kHeight = 256;
// table used to map the name of a Viewer to its KeyNavigatorBehavior
Hashtable m_KeyHashtable = null;
BoundingSphere m_Bounds = null;
public PlatformTest() {
m_KeyHashtable = new Hashtable();
m_Bounds = new BoundingSphere(new Point3d(0, 0, 0), 100);
// get the graphics configuration for the graphics device
GraphicsConfiguration config = SimpleUniverse
.getPreferredConfiguration();
// create the first canvas, this is the top-down view
Canvas3D c = new Canvas3D(config);
c.setSize(m_kWidth, m_kHeight);
add(c);
// create the second canvas, this is used for "Jim's" Viewer
Canvas3D c2 = new Canvas3D(config);
c2.setSize(m_kWidth, m_kHeight);
add(c2);
// create the third canvas, this is used for "Dan's" Viewer
Canvas3D c3 = new Canvas3D(config);
c3.setSize(m_kWidth, m_kHeight);
add(c3);
// Create the simple environment
BranchGroup scene = createSceneGraph();
// create the first Viewer, this is a static top-down view
// create a ViewingPlatform with 2 TransformGroups above the
// ViewPlatform
ViewingPlatform vp = new ViewingPlatform(2);
// create the Viewer and attach to the first canvas
Viewer viewer = new Viewer(c);
// rotate and position the first Viewer above the environment
Transform3D t3d = new Transform3D();
t3d.rotX(Math.PI / 2.0);
t3d.setTranslation(new Vector3d(0, 0, -40));
t3d.invert();
MultiTransformGroup mtg = vp.getMultiTransformGroup();
mtg.getTransformGroup(0).setTransform(t3d);
// create a SimpleUniverse from the ViewingPlatform and Viewer
SimpleUniverse u = new SimpleUniverse(vp, viewer);
// add the geometry to the scenegraph
u.addBranchGraph(scene);
// add two more Viewers to the scenegraph
u.getLocale().addBranchGraph(
createViewer(c2, "Jim", new Color3f(0.1f, 1.0f, 1.0f), -5, 8));
u.getLocale().addBranchGraph(
createViewer(c3, "Dan", new Color3f(1.0f, 0.1f, 0.1f), 2, -8));
}
ViewingPlatform createViewer(Canvas3D c, String szName, Color3f objColor,
double x, double z) {
// create a Viewer and attach to its canvas
// a Canvas3D can only be attached to a single Viewer
Viewer viewer2 = new Viewer(c);
// create a ViewingPlatform with 1 TransformGroups above the
// ViewPlatform
ViewingPlatform vp2 = new ViewingPlatform(1);
// create and assign the PlatformGeometry to the Viewer
vp2.setPlatformGeometry(createPlatformGeometry(szName));
// create and assign the ViewerAvatar to the Viewer
viewer2.setAvatar(createViewerAvatar(szName, objColor));
// set the initial position for the Viewer
Transform3D t3d = new Transform3D();
t3d.setTranslation(new Vector3d(x, 0, z));
vp2.getViewPlatformTransform().setTransform(t3d);
// set capabilities on the TransformGroup so that the
// KeyNavigatorBehavior
// can modify the Viewer's position
vp2.getViewPlatformTransform().setCapability(
TransformGroup.ALLOW_TRANSFORM_WRITE);
vp2.getViewPlatformTransform().setCapability(
TransformGroup.ALLOW_TRANSFORM_READ);
// attach a navigation behavior to the position of the viewer
KeyNavigatorBehavior key = new KeyNavigatorBehavior(vp2
.getViewPlatformTransform());
key.setSchedulingBounds(m_Bounds);
key.setEnable(false);
// add the KeyNavigatorBehavior to the ViewingPlatform
vp2.addChild(key);
// set the ViewingPlatform for the Viewer
viewer2.setViewingPlatform(vp2);
// associate the name of the Viewer with its KeyNavigatorBehavior
m_KeyHashtable.put(szName, key);
// create a button to switch the Viewer ON.
Button button = new Button(szName);
button.addActionListener(this);
add(button);
return vp2;
}
// create a tiled environment from -12 to +12. The environment
// is created from a QuadArray. The environment is surrounded by a ColorCube
// "wall" that is 2 units high (from Z = -1 to Z = 1).
public BranchGroup createSceneGraph() {
final int LAND_WIDTH = 12;
final float LAND_HEIGHT = -1.0f;
final int LAND_LENGTH = 12;
final int nTileSize = 2;
// calculate how many vertices we need to store all the "tiles"
// that compose the QuadArray.
final int nNumTiles = ((LAND_LENGTH / nTileSize) * 2)
* ((LAND_WIDTH / nTileSize) * 2);
final int nVertexCount = 4 * nNumTiles;
Point3f[] coordArray = new Point3f[nVertexCount];
Point2f[] texCoordArray = new Point2f[nVertexCount];
// create an Appearance and load a texture
Appearance app = new Appearance();
Texture tex = new TextureLoader("land.jpg", this).getTexture();
app.setTexture(tex);
// create the parent BranchGroup
BranchGroup bg = new BranchGroup();
int nItem = 0;
// loop over all the tiles in the environment
for (int x = -LAND_WIDTH; x <= LAND_WIDTH; x += nTileSize) {
for (int z = -LAND_LENGTH; z <= LAND_LENGTH; z += nTileSize) {
// if we are on the border of the environment create a
// TransformGroup to position a ColorCube to create a "wall"
if (x == -LAND_WIDTH || x == LAND_WIDTH || z == -LAND_LENGTH
|| z == LAND_LENGTH) {
TransformGroup tg = new TransformGroup();
Transform3D t3d = new Transform3D();
t3d.setTranslation(new Vector3d(x, 0, z));
tg.setTransform(t3d);
tg.addChild(new ColorCube(nTileSize / 2));
bg.addChild(tg);
}
// if we are not on the last row or column create a "tile"
// and add to the QuadArray. Use CCW winding and assign texture
// coordinates.
if (z < LAND_LENGTH && x < LAND_WIDTH) {
coordArray[nItem] = new Point3f(x, LAND_HEIGHT, z);
texCoordArray[nItem++] = new Point2f(0, 0);
coordArray[nItem] = new Point3f(x, LAND_HEIGHT, z
+ nTileSize);
texCoordArray[nItem++] = new Point2f(1, 0);
coordArray[nItem] = new Point3f(x + nTileSize, LAND_HEIGHT,
z + nTileSize);
texCoordArray[nItem++] = new Point2f(1, 1);
coordArray[nItem] = new Point3f(x + nTileSize, LAND_HEIGHT,
z);
texCoordArray[nItem++] = new Point2f(0, 1);
}
}
}
// create a GeometryInfo and generate Normal vectors
// for the QuadArray that was populated.
GeometryInfo gi = new GeometryInfo(GeometryInfo.QUAD_ARRAY);
gi.setCoordinates(coordArray);
gi.setTextureCoordinates(texCoordArray);
NormalGenerator normalGenerator = new NormalGenerator();
normalGenerator.generateNormals(gi);
// wrap the GeometryArray in a Shape3D
Shape3D shape = new Shape3D(gi.getGeometryArray(), app);
// add the Shape3D to the parent BranchGroup
bg.addChild(shape);
// create some lights for the scene
Color3f lColor1 = new Color3f(0.7f, 0.7f, 0.7f);
Vector3f lDir1 = new Vector3f(-1.0f, -1.0f, -1.0f);
Color3f alColor = new Color3f(0.2f, 0.2f, 0.2f);
AmbientLight aLgt = new AmbientLight(alColor);
aLgt.setInfluencingBounds(m_Bounds);
DirectionalLight lgt1 = new DirectionalLight(lColor1, lDir1);
lgt1.setInfluencingBounds(m_Bounds);
// add the lights to the parent BranchGroup
bg.addChild(aLgt);
bg.addChild(lgt1);
// create a light gray background
Background back = new Background(new Color3f(0.9f, 0.9f, 0.9f));
back.setApplicationBounds(m_Bounds);
bg.addChild(back);
// compile the whole scene
//bg.compile();
return bg;
}
// creates and positions a simple Cone to represent the Viewer.
// The Cone is aligned and scaled such that it is similar to a
// 3D "turtle".... Aaah good old Logo.
ViewerAvatar createViewerAvatar(String szText, Color3f objColor) {
ViewerAvatar viewerAvatar = new ViewerAvatar();
// rotate the Cone so that it is lying down and
// points sharp-end towards the Viewer's field of view.
TransformGroup tg = new TransformGroup();
Transform3D t3d = new Transform3D();
t3d.setEuler(new Vector3d(Math.PI / 2.0, Math.PI, 0));
tg.setTransform(t3d);
// create appearance and material for the Cone
Appearance app = new Appearance();
Color3f black = new Color3f(0.4f, 0.2f, 0.1f);
app.setMaterial(new Material(objColor, black, objColor, black, 90.0f));
// create the Primitive and add to the parent BranchGroup
tg.addChild(new Cone(1, 3, Primitive.GENERATE_NORMALS, app));
viewerAvatar.addChild(tg);
return viewerAvatar;
}
// create a simple Raster text label used to help
// identify the viewer.
PlatformGeometry createPlatformGeometry(String szText) {
PlatformGeometry pg = new PlatformGeometry();
pg.addChild(createLabel(szText, 0f, 2f, 0f));
return pg;
}
// creates a simple Raster text label (similar to Text2D)
private Shape3D createLabel(String szText, float x, float y, float z) {
BufferedImage bufferedImage = new BufferedImage(25, 14,
BufferedImage.TYPE_INT_RGB);
Graphics g = bufferedImage.getGraphics();
g.setColor(Color.white);
g.drawString(szText, 2, 12);
ImageComponent2D imageComponent2D = new ImageComponent2D(
ImageComponent2D.FORMAT_RGB, bufferedImage);
// create the Raster for the image
javax.media.j3d.Raster renderRaster = new javax.media.j3d.Raster(
new Point3f(x, y, z), javax.media.j3d.Raster.RASTER_COLOR, 0,
0, bufferedImage.getWidth(), bufferedImage.getHeight(),
imageComponent2D, null);
return new Shape3D(renderRaster);
}
// Enables the KeyNavigatorBehavior associated with the
// AWT button that was pressed for the Viewer. Disables all other
// KeyNavigatorBehaviors for non-active Viewers.
public void actionPerformed(ActionEvent event) {
KeyNavigatorBehavior key = (KeyNavigatorBehavior) m_KeyHashtable
.get(event.getActionCommand());
Object[] keysArray = m_KeyHashtable.values().toArray();
for (int n = 0; n < keysArray.length; n++) {
KeyNavigatorBehavior keyAtIndex = (KeyNavigatorBehavior) keysArray[n];
keyAtIndex.setEnable(keyAtIndex == key);
if (keyAtIndex == key)
System.out.println("Enabled: " + event.getActionCommand());
}
}
public static void main(String[] args) {
new MainFrame(new PlatformTest(), (int) (m_kWidth * 3.5),
(int) (m_kHeight * 1.1));
}
}
/*******************************************************************************
* Copyright (C) 2001 Daniel Selman
*
* First distributed with the book "Java 3D Programming" by Daniel Selman and
* published by Manning Publications. http://manning.com/selman
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* The license can be found on the WWW at: http://www.fsf.org/copyleft/gpl.html
*
* Or by writing to: Free Software Foundation, Inc., 59 Temple Place - Suite
* 330, Boston, MA 02111-1307, USA.
*
* Authors can be contacted at: Daniel Selman:
This e-mail address is being protected from spam bots, you need JavaScript enabled to view it
*
* If you make changes you think others would like, please contact one of the
* authors or someone at the www.j3d.org web site.
******************************************************************************/
//*****************************************************************************
/**
* Java3dApplet
*
* Base class for defining a Java 3D applet. Contains some useful methods for
* defining views and scenegraphs etc.
*
* @author Daniel Selman
* @version 1.0
*/
//*****************************************************************************
abstract class Java3dApplet extends Applet {
public static int m_kWidth = 300;
public static int m_kHeight = 300;
protected String[] m_szCommandLineArray = null;
protected VirtualUniverse m_Universe = null;
protected BranchGroup m_SceneBranchGroup = null;
protected Bounds m_ApplicationBounds = null;
// protected com.tornadolabs.j3dtree.Java3dTree m_Java3dTree = null;
public Java3dApplet() {
}
public boolean isApplet() {
try {
System.getProperty("user.dir");
System.out.println("Running as Application.");
return false;
} catch (Exception e) {
}
System.out.println("Running as Applet.");
return true;
}
public URL getWorkingDirectory() throws java.net.MalformedURLException {
URL url = null;
try {
File file = new File(System.getProperty("user.dir"));
System.out.println("Running as Application:");
System.out.println(" " + file.toURL());
return file.toURL();
} catch (Exception e) {
}
System.out.println("Running as Applet:");
System.out.println(" " + getCodeBase());
return getCodeBase();
}
public VirtualUniverse getVirtualUniverse() {
return m_Universe;
}
//public com.tornadolabs.j3dtree.Java3dTree getJ3dTree() {
//return m_Java3dTree;
// }
public Locale getFirstLocale() {
java.util.Enumeration e = m_Universe.getAllLocales();
if (e.hasMoreElements() != false)
return (Locale) e.nextElement();
return null;
}
protected Bounds getApplicationBounds() {
if (m_ApplicationBounds == null)
m_ApplicationBounds = createApplicationBounds();
return m_ApplicationBounds;
}
protected Bounds createApplicationBounds() {
m_ApplicationBounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
100.0);
return m_ApplicationBounds;
}
protected Background createBackground() {
Background back = new Background(new Color3f(0.9f, 0.9f, 0.9f));
back.setApplicationBounds(createApplicationBounds());
return back;
}
public void initJava3d() {
// m_Java3dTree = new com.tornadolabs.j3dtree.Java3dTree();
m_Universe = createVirtualUniverse();
Locale locale = createLocale(m_Universe);
BranchGroup sceneBranchGroup = createSceneBranchGroup();
ViewPlatform vp = createViewPlatform();
BranchGroup viewBranchGroup = createViewBranchGroup(
getViewTransformGroupArray(), vp);
createView(vp);
Background background = createBackground();
if (background != null)
sceneBranchGroup.addChild(background);
// m_Java3dTree.recursiveApplyCapability(sceneBranchGroup);
// m_Java3dTree.recursiveApplyCapability(viewBranchGroup);
locale.addBranchGraph(sceneBranchGroup);
addViewBranchGroup(locale, viewBranchGroup);
onDoneInit();
}
protected void onDoneInit() {
// m_Java3dTree.updateNodes(m_Universe);
}
protected double getScale() {
return 1.0;
}
public TransformGroup[] getViewTransformGroupArray() {
TransformGroup[] tgArray = new TransformGroup[1];
tgArray[0] = new TransformGroup();
// move the camera BACK a little...
// note that we have to invert the matrix as
// we are moving the viewer
Transform3D t3d = new Transform3D();
t3d.setScale(getScale());
t3d.setTranslation(new Vector3d(0.0, 0.0, -20.0));
t3d.invert();
tgArray[0].setTransform(t3d);
return tgArray;
}
protected void addViewBranchGroup(Locale locale, BranchGroup bg) {
locale.addBranchGraph(bg);
}
protected Locale createLocale(VirtualUniverse u) {
return new Locale(u);
}
protected BranchGroup createSceneBranchGroup() {
m_SceneBranchGroup = new BranchGroup();
return m_SceneBranchGroup;
}
protected View createView(ViewPlatform vp) {
View view = new View();
PhysicalBody pb = createPhysicalBody();
PhysicalEnvironment pe = createPhysicalEnvironment();
AudioDevice audioDevice = createAudioDevice(pe);
if (audioDevice != null) {
pe.setAudioDevice(audioDevice);
audioDevice.initialize();
}
view.setPhysicalEnvironment(pe);
view.setPhysicalBody(pb);
if (vp != null)
view.attachViewPlatform(vp);
view.setBackClipDistance(getBackClipDistance());
view.setFrontClipDistance(getFrontClipDistance());
Canvas3D c3d = createCanvas3D();
view.addCanvas3D(c3d);
addCanvas3D(c3d);
return view;
}
protected PhysicalBody createPhysicalBody() {
return new PhysicalBody();
}
protected AudioDevice createAudioDevice(PhysicalEnvironment pe) {
JavaSoundMixer javaSoundMixer = new JavaSoundMixer(pe);
if (javaSoundMixer == null)
System.out.println("create of audiodevice failed");
return javaSoundMixer;
}
protected PhysicalEnvironment createPhysicalEnvironment() {
return new PhysicalEnvironment();
}
protected float getViewPlatformActivationRadius() {
return 100;
}
protected ViewPlatform createViewPlatform() {
ViewPlatform vp = new ViewPlatform();
vp.setViewAttachPolicy(View.RELATIVE_TO_FIELD_OF_VIEW);
vp.setActivationRadius(getViewPlatformActivationRadius());
return vp;
}
protected Canvas3D createCanvas3D() {
GraphicsConfigTemplate3D gc3D = new GraphicsConfigTemplate3D();
gc3D.setSceneAntialiasing(GraphicsConfigTemplate.PREFERRED);
GraphicsDevice gd[] = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getScreenDevices();
Canvas3D c3d = new Canvas3D(gd[0].getBestConfiguration(gc3D));
c3d.setSize(getCanvas3dWidth(c3d), getCanvas3dHeight(c3d));
return c3d;
}
protected int getCanvas3dWidth(Canvas3D c3d) {
return m_kWidth;
}
protected int getCanvas3dHeight(Canvas3D c3d) {
return m_kHeight;
}
| |