ExDepthCue - illustrate use of exponential fog for depth-cueing : Fog « 3D « Java

Java
1. 2D Graphics GUI
2. 3D
3. Advanced Graphics
4. Ant
5. Apache Common
6. Chart
7. Collections Data Structure
8. Database SQL JDBC
9. Design Pattern
10. Development Class
11. Email
12. Event
13. File Input Output
14. Game
15. Hibernate
16. J2EE
17. J2ME
18. JDK 6
19. JSP
20. JSTL
21. Language Basics
22. Network Protocol
23. PDF RTF
24. Regular Expressions
25. Security
26. Servlets
27. Spring
28. Swing Components
29. Swing JFC
30. SWT JFace Eclipse
31. Threads
32. Tiny Application
33. Velocity
34. Web Services SOA
35. XML
Microsoft Office Word 2007 Tutorial
Java Tutorial
Java Source Code / Java Documentation
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
C# / C Sharp
C# / CSharp Tutorial
ASP.Net
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
PHP
Python
SQL Server / T-SQL
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Java » 3D » FogScreenshots 
ExDepthCue - illustrate use of exponential fog for depth-cueing
ExDepthCue - illustrate use of exponential fog for depth-cueing

//
//CLASS
//ExDepthCue - illustrate use of exponential fog for depth-cueing
//
//SEE ALSO
//ExLinearFog
//ExExponentialFog
//
//AUTHOR
//David R. Nadeau / San Diego Supercomputer Center
//

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.Appearance;
import javax.media.j3d.Background;
import javax.media.j3d.Behavior;
import javax.media.j3d.BoundingBox;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.Bounds;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.ColoringAttributes;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.Fog;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.Group;
import javax.media.j3d.IndexedQuadArray;
import javax.media.j3d.Light;
import javax.media.j3d.LineAttributes;
import javax.media.j3d.LinearFog;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Switch;
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.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 ExDepthCue extends Java3DFrame {
  //--------------------------------------------------------------
  //  SCENE CONTENT
  //--------------------------------------------------------------

  //
  //  Nodes (updated via menu)
  //
  private LinearFog fog = null;

  private Background background = null;

  private Switch fogSwitch = null;

  //
  //  Build scene
  //
  public Group buildScene() {
    // Get the current color
    Color3f color = (Color3fcolors[currentColor].value;

    // Turn off the example headlight
    setHeadlightEnable(false);

    // Create the scene group
    Group scene = new Group();

    // Create a switch group to hold the fog node. This enables
    // us to turn the fog node on and off via the GUI.
    fogSwitch = new Switch();
    fogSwitch.setCapability(Switch.ALLOW_SWITCH_WRITE);

    // Create influencing bounds
    Bounds worldBounds = new BoundingSphere(new Point3d(0.00.00.0)// Center
        1000.0)// Extent

    // Set the fog color, density, and its influencing bounds
    fog = new LinearFog();
    fog.setColor(color);
    // front and back distances set below
    fog.setCapability(Fog.ALLOW_COLOR_WRITE);
    fog.setCapability(Fog.ALLOW_INFLUENCING_BOUNDS_WRITE);
    fog.setInfluencingBounds(worldBounds);
    fogSwitch.addChild(fog);
    scene.addChild(fogSwitch);
    if (depthCueOnOff)
      fogSwitch.setWhichChild(0)// on
    else
      fogSwitch.setWhichChild(Switch.CHILD_NONE)// off

    // 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
    Group content = buildIsoline();
    scene.addChild(content);

    // Automatically compute good front and back distances for
    // fog to get good depth-cueing. To do this, first get the
    // dimensions of the bounds around the content. Then,
    // set the front distance to be at the center of the content
    // (or closer by a tad) and the back distance at the front
    // distance PLUS half the depth of the content's bounding box
    BoundingSphere sampleSphere = new BoundingSphere();
    BoundingBox sampleBox = new BoundingBox();
    Bounds bounds = content.getBounds();
    double deltaDistance = 0.0;
    double centerZ = 0.0;

    if (bounds == null) {
      // No bounds available. Estimate the values knowing
      // that the above content is what it is.
      centerZ = 0.5// 0.5 closer than true center
      deltaDistance = 2.0;
    else if (bounds.getClass() == sampleSphere.getClass()) {
      BoundingSphere sphereBounds = (BoundingSpherebounds;
      deltaDistance = Math.abs(sphereBounds.getRadius());
      Point3d center = new Point3d();
      sphereBounds.getCenter(center);
      centerZ = center.z + 0.5// 0.5 closer than true center
    else if (bounds.getClass() == sampleBox.getClass()) {
      BoundingBox boxBounds = (BoundingBoxbounds;
      Point3d p1 = new Point3d();
      Point3d p2 = new Point3d();
      boxBounds.getLower(p1);
      boxBounds.getUpper(p2);
      deltaDistance = p2.z - p1.z;
      if (deltaDistance < 0.0)
        deltaDistance *= -1.0;
      if (p1.z > p2.z)
        centerZ = p1.z - deltaDistance / 2.0;
      else
        centerZ = p2.z - deltaDistance / 2.0;
      centerZ += 0.5// 0.5 closer than true center
    else {
      System.err.println("Unknown bounds type");
    }

    // Set front distance to the distance from the default
    // viewing position (0,0,10) to the center of the bounds.
    fog.setFrontDistance(10.0f (floatcenterZ);

    // Set back distance to the distance from the default
    // viewing position (0,0,10) to the back of the bounds.
    fog.setBackDistance(10.0f (floatcenterZ + (floatdeltaDistance);

    return scene;
  }

  public Group buildIsoline() {
    Group group = new Group();

    //                           alpha theta radius r g b
    group.addChild(buildSurface(3.05.02.1941.0f0.0f0.0f));
    group.addChild(buildSurface(2.04.01.1811.0f0.5f0.0f));
    group.addChild(buildSurface(1.03.00.5061.0f1.0f0.0f));

    return group;
  }

  public Shape3D buildSurface(double freqAlpha, double freqTheta,
      double radius, float red, float green, float blue) {
    int nAngles = 64;
    double amp = radius / 4.0;

    int nAlpha = nAngles / 2;
    double theta, alpha;
    double x, y, z, rprime, r;
    double deltaTheta, deltaAlpha;
    int i, j;
    int i1, i2, i3, i4;

    deltaTheta = 360.0 (nAngles - 1.0);
    deltaAlpha = 180.0 (nAlpha - 1.0);

    // Build an appearance
    Appearance app = new Appearance();

    LineAttributes latt = new LineAttributes();
    latt.setLineWidth(1.0f);
    app.setLineAttributes(latt);

    ColoringAttributes catt = new ColoringAttributes();
    catt.setColor(red, green, blue);
    app.setColoringAttributes(catt);

    PolygonAttributes patt = new PolygonAttributes();
    patt.setCullFace(PolygonAttributes.CULL_NONE);
    patt.setPolygonMode(PolygonAttributes.POLYGON_LINE);
    app.setPolygonAttributes(patt);

    // Compute coordinates
    double[] coordinates = new double[nAlpha * nAngles * 3];
    alpha = 90.0;
    int n = 0;
    for (i = 0; i < nAlpha; i++) {
      theta = 0.0;
      for (j = 0; j < nAngles; j++) {
        r = radius
            + amp
            * Math
                .sin((freqAlpha
                    ((doublei / (double) (nAlpha - 1)) + freqTheta
                    ((doublej / (double) (nAngles - 1)))
                    2.0 * Math.PI);
        y = r * Math.sin(alpha / 180.0 * Math.PI);
        rprime = y / Math.tan(alpha / 180.0 * Math.PI);
        x = rprime * Math.cos(theta / 180.0 * Math.PI);
        z = rprime * Math.sin(theta / 180.0 * Math.PI);

        coordinates[n + 0= x;
        coordinates[n + 1= y;
        coordinates[n + 2= z;
        n += 3;
        theta += deltaTheta;
      }
      alpha -= deltaAlpha;
    }

    // Compute coordinate indexes
    int[] indexes = new int[(nAlpha - 1* nAngles * 4];
    n = 0;
    for (i = 0; i < nAlpha - 1; i++) {
      for (j = 0; j < nAngles; j++) {
        i1 = i * nAngles + j;
        if (j == nAngles - 1) {
          i2 = i1 - j;
          i3 = (i + 1* nAngles;
        else {
          i2 = i1 + 1;
          i3 = (i + 1* nAngles + j + 1;
        }
        i4 = (i + 1* nAngles + j;

        indexes[n + 0= i1;
        indexes[n + 1= i2;
        indexes[n + 2= i3;
        indexes[n + 3= i4;
        n += 4;
      }
    }

    // Build the shape
    IndexedQuadArray lines = new IndexedQuadArray(coordinates.length / 3// Number
                                        // of
                                        // coordinates
        GeometryArray.COORDINATES, // coordinates only
        indexes.length)// Number of indexes
    lines.setCoordinates(0, coordinates);
    lines.setCoordinateIndices(0, indexes);

    Shape3D shape = new Shape3D(lines, app);

    return shape;
  }

  //--------------------------------------------------------------
  //  USER INTERFACE
  //--------------------------------------------------------------

  //
  //  Main
  //
  public static void main(String[] args) {
    ExDepthCue ex = new ExDepthCue();
    ex.initialize(args);
    ex.buildUniverse();
    ex.showFrame();
  }

  //  Depth cueing on/off
  private boolean depthCueOnOff = true;

  private CheckboxMenuItem depthCueOnOffMenu = 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 = 3;

  private CheckboxMenu colorMenu = null;

  //
  //  Initialize the GUI (application and applet)
  //
  public void initialize(String[] args) {
    // Initialize the window, menubar, etc.
    super.initialize(args);
    exampleFrame.setTitle("Java 3D ExDepthCue Example");

    //
    //  Add a menubar menu to change node parameters
    //    Depth cueing
    //    Depth-cue color -->
    //

    Menu m = new Menu("Depth Cueing");

    depthCueOnOffMenu = new CheckboxMenuItem("Depth cueing", depthCueOnOff);
    depthCueOnOffMenu.addItemListener(this);
    m.add(depthCueOnOffMenu);

    colorMenu = new CheckboxMenu("Depth-cue color", colors, currentColor,
        this);
    m.add(colorMenu);

    exampleMenuBar.add(m);
  }

  //
  //  Handle checkboxes and menu choices
  //
  public void checkboxChanged(CheckboxMenu menu, int check) {
    if (menu == colorMenu) {
      // Change the fog color and background color
      currentColor = check;
      Color3f color = (Color3fcolors[check].value;
      fog.setColor(color);
      background.setColor(color);
      return;
    }

    // Handle all other checkboxes
    super.checkboxChanged(menu, check);
  }

  public void itemStateChanged(ItemEvent event) {
    Object src = event.getSource();

    // Check if depth-cueing is enabled
    if (src == depthCueOnOffMenu) {
      depthCueOnOff = depthCueOnOffMenu.getState();
      if (depthCueOnOff) {
        // If on, enable color menu and fog
        colorMenu.setEnabled(true);
        fogSwitch.setWhichChild(0)// on
      else {
        // If off, disable color menu and fog
        colorMenu.setEnabled(false);
        fogSwitch.setWhichChild(Switch.CHILD_NONE)// off
      }
    }

    // Handle all other checkboxes
    super.itemStateChanged(event);
  }
}

/**
 * The Example class is a base class extended by example applications. The class
 * provides basic features to create a top-level frame, add a menubar and
 * Canvas3D, build the universe, set up "examine" and "walk" style navigation
 * behaviors, and provide hooks so that subclasses can add 3D content to the
 * example's universe.
 * <P>
 * Using this Example class simplifies the construction of example applications,
 * enabling the author to focus upon 3D content and not the busywork of creating
 * windows, menus, and universes.
 
 @version 1.0, 98/04/16
 @author David R. Nadeau, San Diego Supercomputer Center
 */

class Java3DFrame extends Applet implements WindowListener, ActionListener,
    ItemListener, CheckboxMenuListener {
  //  Navigation types
  public final static int Walk = 0;

  public final static int Examine = 1;

  //  Should the scene be compiled?
  private boolean shouldCompile = true;

  //  GUI objects for our subclasses
  protected Java3DFrame example = null;

  protected Frame exampleFrame = null;

  protected MenuBar exampleMenuBar = null;

  protected Canvas3D exampleCanvas = null;

  protected TransformGroup exampleViewTransform = null;

  protected TransformGroup exampleSceneTransform = null;

  protected boolean debug = false;

  //  Private GUI objects and state
  private boolean headlightOnOff = true;

  private int navigationType = Examine;

  private CheckboxMenuItem headlightMenuItem = null;

  private CheckboxMenuItem walkMenuItem = null;

  private CheckboxMenuItem examineMenuItem = null;

  private DirectionalLight headlight = null;

  private ExamineViewerBehavior examineBehavior = null;

  private WalkViewerBehavior walkBehavior = null;

  //--------------------------------------------------------------
  //  ADMINISTRATION
  //--------------------------------------------------------------

  /**
   * The main program entry point when invoked as an application. Each example
   * application that extends this class must define their own main.
   
   @param args
   *            a String array of command-line arguments
   */
  public static void main(String[] args) {
    Java3DFrame ex = new Java3DFrame();
    ex.initialize(args);
    ex.buildUniverse();
    ex.showFrame();
  }

  /**
   * Constructs a new Example object.
   
   @return a new Example that draws no 3D content
   */
  public Java3DFrame() {
    // Do nothing
  }

  /**
   * Initializes the application when invoked as an applet.
   */
  public void init() {
    // Collect properties into String array
    String[] args = new String[2];
    // NOTE: to be done still...

    this.initialize(args);
    this.buildUniverse();
    this.showFrame();

    // NOTE: add something to the browser page?
  }

  /**
   * Initializes the Example by parsing command-line arguments, building an
   * AWT Frame, constructing a menubar, and creating the 3D canvas.
   
   @param args
   *            a String array of command-line arguments
   */
  protected void initialize(String[] args) {
    example = this;

    // Parse incoming arguments
    parseArgs(args);

    // Build the frame
    if (debug)
      System.err.println("Building GUI...");
    exampleFrame = new Frame();
    exampleFrame.setSize(640480);
    exampleFrame.setTitle("Java 3D Example");
    exampleFrame.setLayout(new BorderLayout());

    // Set up a close behavior
    exampleFrame.addWindowListener(this);

    // Create a canvas
    exampleCanvas = new Canvas3D(null);
    exampleCanvas.setSize(630460);
    exampleFrame.add("Center", exampleCanvas);

    // Build the menubar
    exampleMenuBar = this.buildMenuBar();
    exampleFrame.setMenuBar(exampleMenuBar);

    // Pack
    exampleFrame.pack();
    exampleFrame.validate();
    //    exampleFrame.setVisible( true );
  }

  /**
   * Parses incoming command-line arguments. Applications that subclass this
   * class may override this method to support their own command-line
   * arguments.
   
   @param args
   *            a String array of command-line arguments
   */
  protected void parseArgs(String[] args) {
    for (int i = 0; i < args.length; i++) {
      if (args[i].equals("-d"))
        debug = true;
    }
  }

  //--------------------------------------------------------------
  //  SCENE CONTENT
  //--------------------------------------------------------------

  /**
   * Builds the 3D universe by constructing a virtual universe (via
   * SimpleUniverse), a view platform (via SimpleUniverse), and a view (via
   * SimpleUniverse). A headlight is added and a set of behaviors initialized
   * to handle navigation types.
   */
  protected void buildUniverse() {
    //
    //  Create a SimpleUniverse object, which builds:
    //
    //    - a Locale using the given hi-res coordinate origin
    //
    //    - a ViewingPlatform which in turn builds:
    //          - a MultiTransformGroup with which to move the
    //            the ViewPlatform about
    //
    //          - a ViewPlatform to hold the view
    //
    //          - a BranchGroup to hold avatar geometry (if any)
    //
    //          - a BranchGroup to hold view platform
    //            geometry (if any)
    //
    //    - a Viewer which in turn builds:
    //          - a PhysicalBody which characterizes the user's
    //            viewing preferences and abilities
    //
    //          - a PhysicalEnvironment which characterizes the
    //            user's rendering hardware and software
    //
    //          - a JavaSoundMixer which initializes sound
    //            support within the 3D environment
    //
    //          - a View which renders the scene into a Canvas3D
    //
    //  All of these actions could be done explicitly, but
    //  using the SimpleUniverse utilities simplifies the code.
    //
    if (debug)
      System.err.println("Building scene graph...");
    SimpleUniverse universe = new SimpleUniverse(null, // Hi-res coordinate
        // for the origin -
        // use default
        1// Number of transforms in MultiTransformGroup
        exampleCanvas, // Canvas3D into which to draw
        null)// URL for user configuration file - use defaults

    //
    //  Get the viewer and create an audio device so that
    //  sound will be enabled in this content.
    //
    Viewer viewer = universe.getViewer();
    viewer.createAudioDevice();

    //
    //  Get the viewing platform created by SimpleUniverse.
    //  From that platform, get the inner-most TransformGroup
    //  in the MultiTransformGroup. That inner-most group
    //  contains the ViewPlatform. It is this inner-most
    //  TransformGroup we need in order to:
    //
    //    - add a "headlight" that always aims forward from
    //       the viewer
    //
    //    - change the viewing direction in a "walk" style
    //
    //  The inner-most TransformGroup's transform will be
    //  changed by the walk behavior (when enabled).
    //
    ViewingPlatform viewingPlatform = universe.getViewingPlatform();
    exampleViewTransform = viewingPlatform.getViewPlatformTransform();

    //
    //  Create a "headlight" as a forward-facing directional light.
    //  Set the light's bounds to huge. Since we want the light
    //  on the viewer's "head", we need the light within the
    //  TransformGroup containing the ViewPlatform. The
    //  ViewingPlatform class creates a handy hook to do this
    //  called "platform geometry". The PlatformGeometry class is
    //  subclassed off of BranchGroup, and is intended to contain
    //  a description of the 3D platform itself... PLUS a headlight!
    //  So, to add the headlight, create a new PlatformGeometry group,
    //  add the light to it, then add that platform geometry to the
    //  ViewingPlatform.
    //
    BoundingSphere allBounds = new BoundingSphere(
        new Point3d(0.00.00.0)100000.0);

    PlatformGeometry pg = new PlatformGeometry();
    headlight = new DirectionalLight();
    headlight.setColor(White);
    headlight.setDirection(new Vector3f(0.0f0.0f, -1.0f));
    headlight.setInfluencingBounds(allBounds);
    headlight.setCapability(Light.ALLOW_STATE_WRITE);
    pg.addChild(headlight);
    viewingPlatform.setPlatformGeometry(pg);

    //
    //  Create the 3D content BranchGroup, containing:
    //
    //    - a TransformGroup who's transform the examine behavior
    //      will change (when enabled).
    //
    //    - 3D geometry to view
    //
    // Build the scene root
    BranchGroup sceneRoot = new BranchGroup();

    // Build a transform that we can modify
    exampleSceneTransform = new TransformGroup();
    exampleSceneTransform
        .setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    exampleSceneTransform
        .setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    exampleSceneTransform.setCapability(Group.ALLOW_CHILDREN_EXTEND);

    //
    //  Build the scene, add it to the transform, and add
    //  the transform to the scene root
    //
    if (debug)
      System.err.println("  scene...")