|
This Java tip illustrates the use of exponential fog in Java 3D scenes.
An ExponentialFog node is added to apply fog of varying thickness.
import java.applet.Applet;
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.CheckboxMenuItem;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Frame;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.File;
import java.util.Enumeration;
import java.util.EventListener;
import javax.media.j3d.AmbientLight;
import javax.media.j3d.Appearance;
import javax.media.j3d.Background;
import javax.media.j3d.Behavior;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.ExponentialFog;
import javax.media.j3d.Fog;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.Group;
import javax.media.j3d.IndexedQuadArray;
import javax.media.j3d.IndexedTriangleStripArray;
import javax.media.j3d.Light;
import javax.media.j3d.Link;
import javax.media.j3d.Material;
import javax.media.j3d.Shape3D;
import javax.media.j3d.SharedGroup;
import javax.media.j3d.Texture;
import javax.media.j3d.TextureAttributes;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.WakeupCriterion;
import javax.media.j3d.WakeupOnAWTEvent;
import javax.media.j3d.WakeupOnElapsedFrames;
import javax.media.j3d.WakeupOr;
import javax.vecmath.Color3f;
import javax.vecmath.Matrix4d;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;
import com.sun.j3d.utils.geometry.Primitive;
import com.sun.j3d.utils.image.TextureLoader;
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.ViewingPlatform;
public class ExExponentialFog extends Java3DFrame {
//--------------------------------------------------------------
// SCENE CONTENT
//--------------------------------------------------------------
//
// Nodes (updated via menu)
//
private ExponentialFog fog = null;
private Background background = null;
//
// Build scene
//
public Group buildScene() {
// Get the current color
Color3f color = (Color3f) colors[currentColor].value;
float density = ((Float) densities[currentDensity].value).floatValue();
// Turn off the example headlight
setHeadlightEnable(false);
// Default to walk navigation
setNavigationType(Walk);
// Create the scene group
Group scene = new Group();
// BEGIN EXAMPLE TOPIC
// Create influencing bounds
BoundingSphere worldBounds = new BoundingSphere(new Point3d(0.0, 0.0,
0.0), // Center
1000.0); // Extent
// Set the fog color, density, and its influencing bounds
fog = new ExponentialFog();
fog.setColor(color);
fog.setDensity(density);
fog.setCapability(Fog.ALLOW_COLOR_WRITE);
fog.setCapability(ExponentialFog.ALLOW_DENSITY_WRITE);
fog.setInfluencingBounds(worldBounds);
scene.addChild(fog);
// END EXAMPLE TOPIC
// Set the background color and its application bounds
// Usually, the background color should match the fog color
// or the results look odd.
background = new Background();
background.setColor(color);
background.setApplicationBounds(worldBounds);
background.setCapability(Background.ALLOW_COLOR_WRITE);
scene.addChild(background);
// Build foreground geometry
scene.addChild(new ColumnScene(this));
return scene;
}
//--------------------------------------------------------------
// USER INTERFACE
//--------------------------------------------------------------
//
// Main
//
public static void main(String[] args) {
ExExponentialFog ex = new ExExponentialFog();
ex.initialize(args);
ex.buildUniverse();
ex.showFrame();
}
// Coupled background and fog color
private boolean coupledBackgroundOnOff = true;
private CheckboxMenuItem coupledBackgroundOnOffMenu = null;
// Color menu choices
private NameValue[] colors = { new NameValue("White", White),
new NameValue("Gray", Gray), new NameValue("Dark Gray", DarkGray),
new NameValue("Black", Black), new NameValue("Red", Red),
new NameValue("Dark Red", DarkRed), new NameValue("Green", Green),
new NameValue("Dark Green", DarkGreen),
new NameValue("Blue", Blue), new NameValue("Dark Blue", DarkBlue), };
private int currentColor = 0;
private int currentBackgroundColor = currentColor;
private CheckboxMenu colorMenu = null;
private CheckboxMenu backgroundColorMenu = null;
// Density menu choices
private NameValue[] densities = { new NameValue("No fog", new Float(0.0f)),
new NameValue("Haze (0.5)", new Float(0.5f)),
new NameValue("Light fog (1.0)", new Float(1.0f)),
new NameValue("Heavy fog (2.0)", new Float(2.0f)), };
private int currentDensity = 0;
private CheckboxMenu densityMenu = null;
//
// Initialize the GUI (application and applet)
//
public void initialize(String[] args) {
// Initialize the window, menubar, etc.
super.initialize(args);
exampleFrame.setTitle("Java 3D ExponentialFog Example");
//
// Add a menubar menu to change node parameters
// Coupled background color
// Background color -->
// Fog color -->
// Fog density -->
//
Menu m = new Menu("ExponentialFog");
coupledBackgroundOnOffMenu = new CheckboxMenuItem(
"Couple background color", coupledBackgroundOnOff);
coupledBackgroundOnOffMenu.addItemListener(this);
m.add(coupledBackgroundOnOffMenu);
backgroundColorMenu = new CheckboxMenu("Background color", colors,
currentBackgroundColor, this);
m.add(backgroundColorMenu);
backgroundColorMenu.setEnabled(!coupledBackgroundOnOff);
colorMenu = new CheckboxMenu("Fog color", colors, currentColor, this);
m.add(colorMenu);
densityMenu = new CheckboxMenu("Fog density", densities,
currentDensity, this);
m.add(densityMenu);
exampleMenuBar.add(m);
}
//
// Handle checkboxes and menu choices
//
public void checkboxChanged(CheckboxMenu menu, int check) {
if (menu == backgroundColorMenu) {
// Change the background color
currentBackgroundColor = check;
Color3f color = (Color3f) colors[check].value;
background.setColor(color);
return;
}
if (menu == colorMenu) {
// Change the fog color
currentColor = check;
Color3f color = (Color3f) colors[check].value;
fog.setColor(color);
// If background is coupled, set the background color
if (coupledBackgroundOnOff) {
currentBackgroundColor = currentColor;
backgroundColorMenu.setCurrent(check);
background.setColor(color);
}
return;
}
if (menu == densityMenu) {
// Change the fog density
currentDensity = check;
float density = ((Float) densities[currentDensity].value)
.floatValue();
fog.setDensity(density);
return;
}
// Handle all other checkboxes
super.checkboxChanged(menu, check);
}
public void itemStateChanged(ItemEvent event) {
Object src = event.getSource();
// Check if it is the coupled background choice
if (src == coupledBackgroundOnOffMenu) {
coupledBackgroundOnOff = coupledBackgroundOnOffMenu.getState();
if (coupledBackgroundOnOff) {
currentBackgroundColor = currentColor;
backgroundColorMenu.setCurrent(currentColor);
Color3f color = (Color3f) colors[currentColor].value;
background.setColor(color);
backgroundColorMenu.setEnabled(false);
} else {
backgroundColorMenu.setEnabled(true);
}
}
// Handle all other checkboxes
super.itemStateChanged(event);
}
}
//
//CLASS
//ColumnScene - shapes and lights for a scene with gothic columns
//
//DESCRIPTION
//This class builds a scene containing a stone floor, a set of
//marble columns, plus appropriate lighting. The scene is used in
//several of the examples to provide content to affect with lights,
//background colors and images, and so forth.
//
//SEE ALSO
//ExExponentialFog
//ExLinearFog
//
//AUTHOR
//David R. Nadeau / San Diego Supercomputer Center
//
class ColumnScene extends Group {
//--------------------------------------------------------------
// SCENE CONTENT
//--------------------------------------------------------------
// Construction parameters
private final static float ColumnHeight = 3.0f;
private final static float ColumnRadius = 0.2f;
private final static float ColumnDepthSpacing = 6.0f;
private final static float ColumnSideOffset = 1.0f;
private final static int NumberOfColumns = 4;
private final static float WalkwayWidth = 3.0f;
private final static float WalkwayDepth = ((float) NumberOfColumns - 1)
* ColumnDepthSpacing + 4.0f * WalkwayWidth;
private final static float LawnWidth = 4.0f * WalkwayWidth;
private final static float LawnDepth = WalkwayDepth;
private Texture columnTex = null;
//
// Build a single column in a shared group
//
private SharedGroup buildSharedColumn() {
Appearance columnApp = new Appearance();
Material columnMat = new Material();
columnMat.setAmbientColor(0.6f, 0.6f, 0.6f);
columnMat.setDiffuseColor(1.0f, 1.0f, 1.0f);
columnMat.setSpecularColor(0.0f, 0.0f, 0.0f);
columnApp.setMaterial(columnMat);
TextureAttributes columnTexAtt = new TextureAttributes();
columnTexAtt.setTextureMode(TextureAttributes.MODULATE);
columnTexAtt.setPerspectiveCorrectionMode(TextureAttributes.NICEST);
columnApp.setTextureAttributes(columnTexAtt);
if (columnTex != null)
columnApp.setTexture(columnTex);
GothicColumn columnShape = new GothicColumn(ColumnHeight, // height
ColumnRadius, // radius
GothicColumn.BUILD_TOP, // flags
columnApp); // appearance
// BEGIN EXAMPLE TOPIC
// Build a shared group to hold the column shape
SharedGroup column = new SharedGroup();
column.addChild(columnShape);
// END EXAMPLE TOPIC
return column;
}
//
// Used a column in a shared group and link to it
// several times to build a double row of columns
//
private Group buildColumns(SharedGroup column) {
Group group = new Group();
// Place columns
float x = -ColumnSideOffset;
float y = -1.6f;
float z = ColumnDepthSpacing;
float xSpacing = 2.0f * ColumnSideOffset;
float zSpacing = -ColumnDepthSpacing;
// BEGIN EXAMPLE TOPIC
Vector3f trans = new Vector3f();
Transform3D tr = new Transform3D();
TransformGroup tg;
for (int i = 0; i < NumberOfColumns; i++) {
// Left link
trans.set(x, y, z);
tr.set(trans);
tg = new TransformGroup(tr);
tg.addChild(new Link(column));
group.addChild(tg);
// Right link
trans.set(x + xSpacing, y, z);
tr.set(trans);
tg = new TransformGroup(tr);
tg.addChild(new Link(column));
group.addChild(tg);
z += zSpacing;
}
// END EXAMPLE TOPIC
return group;
}
//
// Build a scene containing multiple columns
//
public ColumnScene(Component observer) {
BoundingSphere worldBounds = new BoundingSphere(new Point3d(0.0, 0.0,
0.0), // Center
1000.0); // Extent
// Add a few lights
AmbientLight ambient = new AmbientLight();
ambient.setEnable(true);
ambient.setColor(new Color3f(0.2f, 0.2f, 0.2f));
ambient.setInfluencingBounds(worldBounds);
addChild(ambient);
DirectionalLight dir1 = new DirectionalLight();
dir1.setEnable(true);
dir1.setColor(new Color3f(1.0f, 1.0f, 1.0f));
dir1.setDirection(new Vector3f(0.8f, -0.35f, 0.5f));
dir1.setInfluencingBounds(worldBounds);
addChild(dir1);
DirectionalLight dir2 = new DirectionalLight();
dir2.setEnable(true);
dir2.setColor(new Color3f(0.75f, 0.75f, 1.0f));
dir2.setDirection(new Vector3f(-0.7f, -0.35f, -0.5f));
dir2.setInfluencingBounds(worldBounds);
addChild(dir2);
// Load textures
TextureLoader texLoader = new TextureLoader("grass06.jpg", observer);
Texture grassTex = texLoader.getTexture();
if (grassTex == null)
System.err.println("Cannot load grass06.jpg texture");
else {
grassTex.setBoundaryModeS(Texture.WRAP);
grassTex.setBoundaryModeT(Texture.WRAP);
grassTex.setMinFilter(Texture.NICEST);
grassTex.setMagFilter(Texture.NICEST);
grassTex.setMipMapMode(Texture.BASE_LEVEL);
grassTex.setEnable(true);
}
texLoader = new TextureLoader("marble10.jpg", observer);
Texture walkTex = texLoader.getTexture();
if (walkTex == null)
System.err.println("Cannot load marble10.jpg texture");
else {
walkTex.setBoundaryModeS(Texture.WRAP);
walkTex.setBoundaryModeT(Texture.WRAP);
walkTex.setMinFilter(Texture.NICEST);
walkTex.setMagFilter(Texture.NICEST);
walkTex.setMipMapMode(Texture.BASE_LEVEL);
walkTex.setEnable(true);
}
texLoader = new TextureLoader("granite07rev.jpg", observer);
columnTex = texLoader.getTexture();
if (columnTex == null)
System.err.println("Cannot load granite07rev.jpg texture");
else {
columnTex.setBoundaryModeS(Texture.WRAP);
columnTex.setBoundaryModeT(Texture.WRAP);
columnTex.setMinFilter(Texture.NICEST);
columnTex.setMagFilter(Texture.NICEST);
columnTex.setMipMapMode(Texture.BASE_LEVEL);
columnTex.setEnable(true);
}
//
// Build the ground
// +-----+---+-----+
// | | | |
// | G | W | G |
// | | | |
// +-----+---+-----+
//
// where "G" is grass, and "W" is a walkway between columns
//
Vector3f trans = new Vector3f();
Transform3D tr = new Transform3D();
TransformGroup tg;
// Walkway appearance
Appearance walkApp = new Appearance();
Material walkMat = new Material();
walkMat.setAmbientColor(0.5f, 0.5f, 0.5f);
walkMat.setDiffuseColor(1.0f, 1.0f, 1.0f);
walkMat.setSpecularColor(0.0f, 0.0f, 0.0f);
walkApp.setMaterial(walkMat);
TextureAttributes walkTexAtt = new TextureAttributes();
walkTexAtt.setTextureMode(TextureAttributes.MODULATE);
walkTexAtt.setPerspectiveCorrectionMode(TextureAttributes.NICEST);
tr.setIdentity();
tr.setScale(new Vector3d(1.0, 6.0, 1.0));
walkTexAtt.setTextureTransform(tr);
walkApp.setTextureAttributes(walkTexAtt);
if (walkTex != null)
walkApp.setTexture(walkTex);
// Grass appearance
Appearance grassApp = new Appearance();
Material grassMat = new Material();
grassMat.setAmbientColor(0.5f, 0.5f, 0.5f);
grassMat.setDiffuseColor(1.0f, 1.0f, 1.0f);
grassMat.setSpecularColor(0.0f, 0.0f, 0.0f);
grassApp.setMaterial(grassMat);
TextureAttributes grassTexAtt = new TextureAttributes();
grassTexAtt.setTextureMode(TextureAttributes.MODULATE);
grassTexAtt.setPerspectiveCorrectionMode(TextureAttributes.NICEST);
tr.setIdentity();
tr.setScale(new Vector3d(2.0, 8.0, 1.0));
grassTexAtt.setTextureTransform(tr);
grassApp.setTextureAttributes(grassTexAtt);
if (grassTex != null)
grassApp.setTexture(grassTex);
// Left grass
trans.set(-LawnWidth / 2.0f - WalkwayWidth / 2.0f, -1.6f, 0.0f);
tr.set(trans);
tg = new TransformGroup(tr);
ElevationGrid grass1 = new ElevationGrid(2, // X dimension
2, // Z dimension
LawnWidth, // X spacing
LawnDepth, // Z spacing
grassApp); // appearance
tg.addChild(grass1);
addChild(tg);
// Right grass
trans.set(LawnWidth / 2.0f + WalkwayWidth / 2.0f, -1.6f, 0.0f);
tr.set(trans);
tg = new TransformGroup(tr);
ElevationGrid grass2 = new ElevationGrid(2, // X dimension
2, // Z dimension
LawnWidth, // X spacing
LawnDepth, // Z spacing
grassApp); // appearance
tg.addChild(grass2);
addChild(tg);
// Walkway
trans.set(0.0f, -1.6f, 0.0f);
tr.set(trans);
tg = new TransformGroup(tr);
ElevationGrid walk = new ElevationGrid(2, // X dimension
2, // Z dimension
WalkwayWidth, // X spacing
WalkwayDepth, // Z spacing
walkApp); // appearance
tg.addChild(walk);
addChild(tg);
//
// Build several columns on the floor
//
SharedGroup column = buildSharedColumn();
Group columns = buildColumns(column);
addChild(columns);
}
}
//
//CLASS
//ElevationGrid - a 3D terrain grid built from a list of heights
//
//DESCRIPTION
//This class creates a 3D terrain on a grid whose X and Z dimensions,
//and row/column spacing are parameters, along with a list of heights
//(elevations), one per grid row/column pair.
//
class ElevationGrid extends Primitive {
// Parameters
protected int xDimension = 0, zDimension = 0;
protected double xSpacing = 0.0, zSpacing = 0.0;
protected double[] heights = null;
// 3D nodes
private Appearance mainAppearance = null;
private Shape3D shape = null;
private IndexedTriangleStripArray tristrip = null;
//
// Construct an elevation grid
//
public ElevationGrid() {
xDimension = 2;
zDimension = 2;
xSpacing = 1.0;
zSpacing = 1.0;
mainAppearance = null;
zeroHeights();
rebuild();
}
public ElevationGrid(int xDim, int zDim) {
xDimension = xDim;
zDimension = zDim;
xSpacing = 1.0;
zSpacing = 1.0;
mainAppearance = null;
zeroHeights();
rebuild();
}
public ElevationGrid(int xDim, int zDim, Appearance app) {
xDimension = xDim;
zDimension = zDim;
xSpacing = 1.0;
zSpacing = 1.0;
mainAppearance = app;
zeroHeights();
rebuild();
}
public ElevationGrid(int xDim, int zDim, double xSpace, double zSpace) {
xDimension = xDim;
zDimension = zDim;
xSpacing = xSpace;
zSpacing = zSpace;
mainAppearance = null;
zeroHeights();
rebuild();
}
public ElevationGrid(int xDim, int zDim, double xSpace, double zSpace,
Appearance app) {
xDimension = xDim;
zDimension = zDim;
xSpacing = xSpace;
zSpacing = zSpace;
mainAppearance = app;
zeroHeights();
rebuild();
}
public ElevationGrid(int xDim, int zDim, double[] h) {
this(xDim, zDim, 1.0, 1.0, h, null);
}
public ElevationGrid(int xDim, int zDim, double[] h, Appearance app) {
this | |