/**
* Creates five sample behaviors and applies them to an object in a scene:
* <p>
* 1. Object Size - displays the size of the geometry in the object 2. Explode -
* explodes the geometry after 10 seconds 3. Stretch - allows the geometry to be
* stretched using the spacebar (simple physics) 4. Bounds - displays the bounds
* of the object 5. FPS - displays frames-per-seconds rendered
*/ public class BehaviorTest extends Java3dApplet implements ExplosionListener,
ActionListener { private static int m_kWidth = 350;
Button rotateButton = new Button("Rotate");
rotateButton.addActionListener(this);
controlPanel.add(rotateButton);
Button objSizeButton = new Button("Object Size");
objSizeButton.addActionListener(this);
controlPanel.add(objSizeButton);
Button explodeButton = new Button("Explode");
explodeButton.addActionListener(this);
controlPanel.add(explodeButton);
Button stretchButton = new Button("Stretch");
stretchButton.addActionListener(this);
controlPanel.add(stretchButton);
Button boundsButton = new Button("Bounds");
boundsButton.addActionListener(this);
controlPanel.add(boundsButton);
Button fpsButton = new Button("FPS");
fpsButton.addActionListener(this);
controlPanel.add(fpsButton);
add(controlPanel, BorderLayout.SOUTH);
}
// handle event from the GUI components we created public void actionPerformed(ActionEvent event) { if (event.getActionCommand().equals("Object Size") != false)
m_SizeBehavior.setEnable(!m_SizeBehavior.getEnable());
else if (event.getActionCommand().equals("Explode") != false)
m_ExplodeBehavior.setEnable(!m_ExplodeBehavior.getEnable());
else if (event.getActionCommand().equals("Stretch") != false)
m_StretchBehavior.setEnable(!m_StretchBehavior.getEnable());
else if (event.getActionCommand().equals("Rotate") != false)
m_RotationInterpolator.setEnable(!m_RotationInterpolator
.getEnable());
else if (event.getActionCommand().equals("Bounds") != false)
m_BoundsBehavior.setEnable(!m_BoundsBehavior.getEnable());
else if (event.getActionCommand().equals("FPS") != false)
m_FpsBehavior.setEnable(!m_FpsBehavior.getEnable());
}
// create a TransformGroup to rotate the hand
TransformGroup objTrans = new TransformGroup();
objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
// create a RotationInterpolator behavior to rotate the hand
Transform3D yAxis = new Transform3D();
Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0,
4000, 0, 0, 0, 0, 0);
public static void main(String[] args) {
BehaviorTest behaviorTest = new BehaviorTest();
behaviorTest.saveCommandLineArguments(args);
new MainFrame(behaviorTest, m_kWidth, m_kHeight);
}
}
//this class implements a simple behavior that
//output the rendered Frames Per Second.
class FpsBehavior extends Behavior {
// the wake up condition for the behavior protected WakeupCondition m_WakeupCondition = null;
protected long m_StartTime = 0;
private final int m_knReportInterval = 100;
public FpsBehavior() {
// save the WakeupCriterion for the behavior
m_WakeupCondition = new WakeupOnElapsedFrames(m_knReportInterval);
}
public void initialize() {
// apply the initial WakeupCriterion
wakeupOn(m_WakeupCondition);
}
public void processStimulus(java.util.Enumeration criteria) { while (criteria.hasMoreElements()) {
WakeupCriterion wakeUp = (WakeupCriterion) criteria.nextElement();
// every N frames, update position of the graphic if (wakeUp instanceof WakeupOnElapsedFrames) { if (m_StartTime > 0) { final long interval = System.currentTimeMillis()
- m_StartTime;
System.out.println("FPS: " + (m_knReportInterval * 1000)
/ interval);
}
m_StartTime = System.currentTimeMillis();
}
}
// assign the next WakeUpCondition, so we are notified again
wakeupOn(m_WakeupCondition);
}
}
//this class implements a simple behavior that
//displays a graphical representation of the Bounds
//of a Node.
class BoundsBehavior extends Behavior {
// the wake up condition for the behavior protected WakeupCondition m_WakeupCondition = null;
// the Node that we are tracking protected Node m_Node = null;
protected TransformGroup m_TransformGroup = null;
protected Switch m_BoundsSwitch = null;
protected Transform3D m_Transform3D = null;
protected Vector3d m_Scale = null;
protected Vector3d m_Vector3d = null;
protected Point3d m_Point3d1 = null;
protected Point3d m_Point3d2 = null;
private final int m_kSphereBounds = 0;
private final int m_kBoxBounds = 1;
public BoundsBehavior(Node node) {
// save the GeometryArray that we are modifying
m_Node = node;
m_Transform3D = new Transform3D();
m_Scale = new Vector3d();
m_Vector3d = new Vector3d();
m_Point3d1 = new Point3d();
m_Point3d2 = new Point3d();
// set the capability bits that the behavior requires
m_Node.setCapability(Node.ALLOW_BOUNDS_READ);
// save the WakeupCriterion for the behavior
m_WakeupCondition = new WakeupOnElapsedFrames(10);
}
public void addBehaviorToParentGroup(Group nodeParentGroup) {
nodeParentGroup.addChild(this);
m_TransformGroup = new TransformGroup();
m_TransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
m_BoundsSwitch = new Switch();
m_BoundsSwitch.setCapability(Switch.ALLOW_SWITCH_WRITE);
Appearance app = new Appearance();
PolygonAttributes polyAttrbutes = new PolygonAttributes();
polyAttrbutes.setPolygonMode(PolygonAttributes.POLYGON_LINE);
polyAttrbutes.setCullFace(PolygonAttributes.CULL_NONE);
app.setPolygonAttributes(polyAttrbutes);
m_BoundsSwitch.addChild(new Sphere(1, app));
ColorCube cube = new ColorCube();
cube.setAppearance(app);
Group g = new Group();
g.addChild(cube);
m_BoundsSwitch.addChild(g);
public void setEnable(boolean bEnable) { super.setEnable(bEnable);
if (m_BoundsSwitch != null) { if (bEnable == false)
m_BoundsSwitch.setWhichChild(Switch.CHILD_NONE);
}
}
public void initialize() {
// apply the initial WakeupCriterion
wakeupOn(m_WakeupCondition);
}
public void processStimulus(java.util.Enumeration criteria) { while (criteria.hasMoreElements()) {
WakeupCriterion wakeUp = (WakeupCriterion) criteria.nextElement();
// every N frames, update position of the graphic if (wakeUp instanceof WakeupOnElapsedFrames) { if (m_TransformGroup != null) {
Bounds bounds = m_Node.getBounds();
int nBoundsType = m_kBoxBounds;
m_Transform3D.setIdentity();
if (bounds instanceof BoundingSphere) {
nBoundsType = m_kSphereBounds;
public ExplodeBehavior(Shape3D shape3D, int nElapsedTime, int nNumFrames,
ExplosionListener listener) {
// allocate a temporary vector
m_Vector = new Vector3f();
m_FrameWakeupCondition = new WakeupOnElapsedFrames(1);
// create the WakeupCriterion for the behavior
m_InitialWakeupCondition = new WakeupOnElapsedTime(m_nElapsedTime);
m_Listener = listener;
// save the GeometryArray that we are modifying
m_GeometryArray = (GeometryArray) m_Shape3D.getGeometry();
if (m_Shape3D.isLive() == false && m_Shape3D.isCompiled() == false) {
// set the capability bits that the behavior requires
m_Shape3D.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
m_Shape3D.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
// make a copy of the object's original appearance
m_Appearance = new Appearance();
m_Appearance = (Appearance) m_Shape3D.getAppearance()
.cloneNodeComponent(true);
// allocate an array for the model coordinates
m_CoordinateArray = new float[3 * m_GeometryArray.getVertexCount()];
// make a copy of the models original coordinates
m_OriginalCoordinateArray = new float[3 * m_GeometryArray
.getVertexCount()];
m_GeometryArray.getCoordinates(0, m_OriginalCoordinateArray);
// start (or restart) the behavior
setEnable(true);
return m_InitialWakeupCondition;
}
public void initialize() {
// apply the initial WakeupCriterion
wakeupOn(m_InitialWakeupCondition);
}
public void processStimulus(java.util.Enumeration criteria) { while (criteria.hasMoreElements()) {
WakeupCriterion wakeUp = (WakeupCriterion) criteria.nextElement();
if (wakeUp instanceof WakeupOnElapsedTime) {
// we are starting the explosion, apply the
// appearance changes we require
PolygonAttributes polyAttribs = new PolygonAttributes(
PolygonAttributes.POLYGON_POINT,
PolygonAttributes.CULL_NONE, 0);
m_Shape3D.getAppearance().setPolygonAttributes(polyAttribs);
PointAttributes pointAttribs = new PointAttributes(3, false);
m_Shape3D.getAppearance().setPointAttributes(pointAttribs);
m_Shape3D.getAppearance().setTexture(null);
m_TransparencyAttributes = new TransparencyAttributes(
TransparencyAttributes.NICEST, 0);
m_TransparencyAttributes
.setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE);
m_Shape3D.getAppearance().setTransparencyAttributes(
m_TransparencyAttributes);
} else {
// we are mid explosion, modify the GeometryArray
m_nFrameNumber++;
// assign the new coordinates
m_GeometryArray.setCoordinates(0, m_CoordinateArray);
}
}
if (m_nFrameNumber < m_nNumFrames) {
// assign the next WakeUpCondition, so we are notified again
wakeupOn(m_FrameWakeupCondition);
} else {
// we are at the end of the explosion
// reapply the original appearance and GeometryArray
// coordinates
setEnable(false);
m_Shape3D.setAppearance(m_Appearance);
//this class implements a simple behavior that
//calculates and prints the size of an object
//based on the vertices in its GeometryArray
class ObjectSizeBehavior extends Behavior {
// the wake up condition for the behavior protected WakeupCondition m_WakeupCondition = null;
// the GeometryArray for the Shape3D that we are querying protected GeometryArray m_GeometryArray = null;
// cache some information on the model to save reallocation protected float[] m_CoordinateArray = null;
protected BoundingBox m_BoundingBox = null;
protected Point3d m_Point = null;;
public ObjectSizeBehavior(GeometryArray geomArray) {
// save the GeometryArray that we are modifying
m_GeometryArray = geomArray;
// set the capability bits that the behavior requires
m_GeometryArray.setCapability(GeometryArray.ALLOW_COORDINATE_READ);
m_GeometryArray.setCapability(GeometryArray.ALLOW_COUNT_READ);
// allocate an array for the coordinates
m_CoordinateArray = new float[3 * m_GeometryArray.getVertexCount()];
// create the BoundingBox used to
// calculate the size of the object
m_BoundingBox = new BoundingBox();
// create a temporary point
m_Point = new Point3d();
// create the WakeupCriterion for the behavior
WakeupCriterion criterionArray[] = new WakeupCriterion[1];
criterionArray[0] = new WakeupOnElapsedFrames(20);
// save the WakeupCriterion for the behavior
m_WakeupCondition = new WakeupOr(criterionArray);
}
public void initialize() {
// apply the initial WakeupCriterion
wakeupOn(m_WakeupCondition);
}
public void processStimulus(java.util.Enumeration criteria) { while (criteria.hasMoreElements()) {
WakeupCriterion wakeUp = (WakeupCriterion) criteria.nextElement();
// every N frames, recalculate the bounds
// for the points in the GeometryArray if (wakeUp instanceof WakeupOnElapsedFrames) {
// get all the coordinates
m_GeometryArray.getCoordinates(0, m_CoordinateArray);
// clear the old BoundingBox
m_BoundingBox.setLower(0, 0, 0);
m_BoundingBox.setUpper(0, 0, 0);
// loop over every vertex and combine with the BoundingBox for (int n = 0; n < m_CoordinateArray.length; n += 3) {
m_Point.x = m_CoordinateArray[n];
m_Point.y = m_CoordinateArray[n + 1];
m_Point.z = m_CoordinateArray[n + 2];
m_BoundingBox.combine(m_Point);
}
System.out.println(m_BoundingBox.toString());
}
}
// assign the next WakeUpCondition, so we are notified again
wakeupOn(m_WakeupCondition);
}
}
//this class implements a more complex behavior.
//the behavior modifies the coordinates within a
//GeometryArray based on simulated forces applied to
//the model. Forces are modeled as springs from the origin
//to every node. Every node has a mass, and hence an
//acceleration. Pressing a key will increase the acceleration
//at each node, upsetting the force equilibrium at each vertex.
//The model will then start to oscillate in size as the springs
//have no "damping" effect.
//
//note: this is a very computationally expensive behavior!
class StretchBehavior extends Behavior {
// the wake up condition for the behavior protected WakeupCondition m_WakeupCondition = null;
// the GeometryArray for the Shape3D that we are modifying protected GeometryArray m_GeometryArray = null;
// cache some information on the model to save reallocation protected float[] m_CoordinateArray = null;
public StretchBehavior(GeometryArray geomArray) {
// save the GeometryArray that we are modifying
m_GeometryArray = geomArray;
// set the capability bits that the behavior requires
m_GeometryArray.setCapability(GeometryArray.ALLOW_COORDINATE_READ);
m_GeometryArray.setCapability(GeometryArray.ALLOW_COORDINATE_WRITE);
m_GeometryArray.setCapability(GeometryArray.ALLOW_COUNT_READ);
// allocate an array for the model coordinates
m_CoordinateArray = new float[3 * m_GeometryArray.getVertexCount()];
// retrieve the models original coordinates - this defines
// the relaxed length of the springs
m_GeometryArray.getCoordinates(0, m_CoordinateArray);
// allocate an array to store the relaxed length
// of the springs from the origin to every vertex
m_LengthArray = new float[m_GeometryArray.getVertexCount()];
// allocate an array to store the mass of every vertex
m_MassArray = new float[m_GeometryArray.getVertexCount()];
// allocate an array to store the acceleration of every vertex
m_AccelerationArray = new float[m_GeometryArray.getVertexCount()];
// allocate a temporary vector
m_Vector = new Vector3f();
float x = 0; float y = 0; float z = 0;
for (int n = 0; n < m_CoordinateArray.length; n += 3) {
// calculate and store the relaxed spring length
x = m_CoordinateArray[n];
y = m_CoordinateArray[n + 1];
z = m_CoordinateArray[n + 2];
// assign the mass for the vertex
m_MassArray[n / 3] = (float) (50 + (5 * Math.random()));
}
// create the WakeupCriterion for the behavior
WakeupCriterion criterionArray[] = new WakeupCriterion[2];
criterionArray[0] = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED);
criterionArray[1] = new WakeupOnElapsedFrames(1);
// save the WakeupCriterion for the behavior
m_WakeupCondition = new WakeupOr(criterionArray);
}
public void initialize() {
// apply the initial WakeupCriterion
wakeupOn(m_WakeupCondition);
}
public void processStimulus(java.util.Enumeration criteria) {
// update the positions of the vertices - regardless of criteria float elongation = 0; float force_spring = 0; float force_mass = 0; float force_sum = 0; float timeFactor = 0.1f; float accel_sum = 0;
// loop over every vertex and calculate its new position
// based on the sum of forces due to acceleration and the
// spring. for (int n = 0; n < m_CoordinateArray.length; n += 3) {
m_Vector.x = m_CoordinateArray[n];
m_Vector.y = m_CoordinateArray[n + 1];
m_Vector.z = m_CoordinateArray[n + 2];
// use squared lengths, as sqrt is costly
elongation = m_LengthArray[n / 3] - m_Vector.lengthSquared();
// apply a portion of the acceleration as change in coordinate.
// based on the normalized vector from the origin to the vertex
m_CoordinateArray[n] += m_Vector.x * timeFactor
* m_AccelerationArray[n / 3];
m_CoordinateArray[n + 1] += m_Vector.y * timeFactor
* m_AccelerationArray[n / 3];
m_CoordinateArray[n + 2] += m_Vector.z * timeFactor
* m_AccelerationArray[n / 3];
}
// assign the new coordinates
m_GeometryArray.setCoordinates(0, m_CoordinateArray);
while (criteria.hasMoreElements()) {
WakeupCriterion wakeUp = (WakeupCriterion) criteria.nextElement();
// if a key was pressed increase the acceleration at the
// vertices a little to upset the equiblibrium if (wakeUp instanceof WakeupOnAWTEvent) { for (int n = 0; n < m_AccelerationArray.length; n++)
m_AccelerationArray[n] += 0.3f;
} else {
// otherwise, print the average acceleration
System.out.print("Average acceleration:\t" + accel_sum
/ m_AccelerationArray.length + "\n");
}
}
// assign the next WakeUpCondition, so we are notified again
wakeupOn(m_WakeupCondition);
}
}
/*******************************************************************************
* 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 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);
You can share your information about this topic using the form below!
Please do not post your questions with this form! Thanks.