java left logo
java middle logo
java right logo
 

Home arrow Other API Tips arrow Java3D arrow Introduction to Java3D API
 
 
Main Menu
Home
Java Tutorials
Book Reviews
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Java Network
Java Forums
Java Blog




Most Visited Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews
Top Rated Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews


Statistics
Registered Users: 4093
Java SE Tips: 614
Java ME Tips: 202
Java EE Tips: 183
Other API Tips: 779
Java Applications: 298
Java Libraries: 209
Java Games: 16
Book Reviews:
 
 
 
Introduction to Java3D API E-mail
User Rating: / 10
PoorBest 
Other API Tips - Java3D

This Tech Tip reprinted with permission by java.sun.com

This tip introduces the Java3D API through three coding examples. In one example, you'll see how to use the Java 3D API to put an object on the screen and position it. A second example shows how to use the Java 3D API to set an object in motion. And a third example shows how to use the API to apply lighting to a scene.

The Java 3D API is a J2SE optional package that is currently available in Solaris and Windows as well as other platforms. You can download the implementation for your computer from the Java 3D API homepage. That page also provides links to tutorials, demonstrations, and sample code -- it also includes a link to the other platforms on which the Java 3D API is available.

Using Java 3D API constructs, you create a 3D virtual world in which you can build and manipulating 3D structures. A familiar analogy might be to an XML document. When you see an XML document rendered in a browser you focus on the content and may not be aware of the underlying tree structure. Similarly the 3D scene information that you view in a Java 3D application as objects in space are also stored in a hierarchy of nodes known as a scene graph. The nodes represent objects, information about position or movement, and information about appearance and lighting.

At the root of this treelike structure is a BranchGroup object. You will need to associate this object with the Canvas3D object that is used to render the scene. For consistency with the examples distributed with Java 3D, this root of the scene graph is named objRoot in each of the examples in this tip.

There are three fundamental steps in creating a 3D world:

  • Create a Canvas3D object.
  • Create a scene graph.
  • Connect the Canvas3D object to a BranchGroup object that points to the root of the scene graph.

These three steps make up the body of the constructor in each of the examples in this tip.

In the first example program below, Static3DWorld, the createCanvas3D() method adjusts the size of a JFrame. The method then creates a canvas3D object and adds it to the center of the JFrame. The Java 3D API specific task is to call the static method getPreferredConfiguration(), and pass the result into the Canvas3D constructor.

The major action in the example is contained in the createSceneGraph() method. The BranchGroup object, objRoot, points to the root of the scene graph. The rotator object is a TransformGroup that rotates an object Pi/4 over the x axis and Pi/4 over the y axis. This TransformGroup is added as a child of the objRoot.

Next a unit cube with each of its six sides emitting a different color is created. This ColorCube is one of the Java 3D API primitives. The ColorCube is added as a child of the rotator object. The createSceneGraph() returns a handle to its root.

Here's the code for Static3DWorld:

    import com.sun.j3d.utils.universe.SimpleUniverse;
    import com.sun.j3d.utils.geometry.ColorCube;
    import javax.media.j3d.BranchGroup;
    import javax.media.j3d.Transform3D;
    import javax.media.j3d.TransformGroup;
    import javax.media.j3d.Canvas3D;
    import javax.swing.JFrame;
    import java.awt.BorderLayout;
    import java.awt.GraphicsConfiguration;

    public class Static3DWorld extends JFrame {
        private Transform3D rotate1 = new Transform3D();
        private Transform3D rotate2 = new Transform3D();

       public Static3DWorld() {
         super("Static3DWorld");
         Canvas3D canvas3D = createCanvas3D();
         BranchGroup scene = createSceneGraph();
         connect(canvas3D, scene);
       }

       private Canvas3D createCanvas3D() {
         setSize(300300);
         getContentPane().setLayout(new BorderLayout());
         GraphicsConfiguration config =
           SimpleUniverse.getPreferredConfiguration();
         Canvas3D canvas3D = new Canvas3D(config);
         setSize(300300);
         getContentPane().add(canvas3D);
         return canvas3D;
       }

       private BranchGroup createSceneGraph() {
         BranchGroup objRoot = new BranchGroup();
         TransformGroup rotator = new TransformGroup(
                                         rotateCube());
         objRoot.addChild(rotator);
         rotator.addChild(new ColorCube(0.3));
         objRoot.compile();
         return objRoot;
       }

       private Transform3D rotateCube() {
         rotate1.rotX(Math.PI / 4.0d);
         rotate2.rotY(Math.PI / 4.0d);
         rotate1.mul(rotate2);
         return rotate1;
       }

       private void connect(Canvas3D canvas3D,
                                    BranchGroup scene) {
         SimpleUniverse simpleU =
                           new SimpleUniverse(canvas3D);
         simpleU.getViewingPlatform().
                           setNominalViewingTransform();
         simpleU.addBranchGraph(scene);
       }

       public static void main(String[] args) {
         new Static3DWorld().setVisible(true);
       }
    }

After you compile and run Static3DWorld, you should see the following displayed:

java3d

Here's a second example that uses the Java 3D API. The example program that follows, Spinning3DWorld, set the cube in motion. Again, the place to begin your examination of the program is the createSceneGraph() method.

     private BranchGroup createSceneGraph() {
        BranchGroup objRoot = new BranchGroup();
        TransformGroup spinner = new TransformGroup();
        spinner.setCapability(
                 TransformGroup.ALLOW_TRANSFORM_WRITE);
        objRoot.addChild(spinner);
        spinner.addChild(new ColorCube(0.3));
        spinner.addChild(makeSpin(spinner));
        return objRoot;
   }

Notice that the scene graph is a bit more complex than in the first example. The spinner is a TransformGroup that is allowed to write back its transform information. Without this line the rotation would be calculated, but would not be represented on the screen. As before, the spinner is added as a child of objRoot, and a ColorCube is created and added as a child of spinner. However, this time the spinner has a second child that takes care of the rotation. The RotationInterpolator object is returned from the makeSpin() method.

   private RotationInterpolator makeSpin(TransformGroup
                                             spinner) {
        RotationInterpolator rotator =
          new RotationInterpolator(new Alpha(-13000),
                                   spinner);
        rotator.setAxisOfRotation(rotateCube());
        BoundingSphere bounds = new BoundingSphere();
        rotator.setSchedulingBounds(bounds);
        return rotator;
   }

A new RotationInterpolator is constructed for the spinner that is passed in. The -1 indicates that it will loop until the program is terminated. Decreasing the second number from 3000 speeds up the rotation, increasing it slows down the rotation. The rotateCube() method from the previous example is used here to set the axis of rotation.

Here's the code for Spinning3DWorld:

    import com.sun.j3d.utils.universe.SimpleUniverse;
    import com.sun.j3d.utils.geometry.ColorCube;
    import javax.media.j3d.BranchGroup;
    import javax.media.j3d.Transform3D;
    import javax.media.j3d.TransformGroup;
    import javax.media.j3d.Canvas3D;
    import javax.media.j3d.Alpha;
    import javax.media.j3d.RotationInterpolator;
    import javax.media.j3d.BoundingSphere;
    import javax.swing.JFrame;
    import java.awt.BorderLayout;
    import java.awt.GraphicsConfiguration;

    public class Spinning3DWorld extends JFrame {
        private Transform3D rotate1 = new Transform3D();
        private Transform3D rotate2 = new Transform3D();

       public Spinning3DWorld() {
         super("Spinning3DWorld");
         Canvas3D canvas3D = createCanvas3D();
         BranchGroup scene = createSceneGraph();
         connect(canvas3D, scene);
       }

       private Canvas3D createCanvas3D() {
         setSize(300300);
         getContentPane().setLayout(new BorderLayout());
         GraphicsConfiguration config =
           SimpleUniverse.getPreferredConfiguration();
         Canvas3D canvas3D = new Canvas3D(config);
         setSize(300300);
         getContentPane().add(canvas3D);
         return canvas3D;
       }

       private BranchGroup createSceneGraph() {
         BranchGroup objRoot = new BranchGroup();
         TransformGroup spinner = new TransformGroup();
         spinner.setCapability(
                  TransformGroup.ALLOW_TRANSFORM_WRITE);
         objRoot.addChild(spinner);
         spinner.addChild(new ColorCube(0.3));
         spinner.addChild(makeSpin(spinner));
         return objRoot;
       }

       private RotationInterpolator makeSpin(
                               TransformGroup spinner) {
         RotationInterpolator rotator =
           new RotationInterpolator(new Alpha(-13000),
                                    spinner);
         rotator.setTransformAxis(rotateCube());
         BoundingSphere bounds = new BoundingSphere();
         rotator.setSchedulingBounds(bounds);
         return rotator;
       }

       private Transform3D rotateCube() {
         rotate1.rotX(Math.PI / 4.0d);
         rotate2.rotY(Math.PI / 3.0d);
         rotate1.mul(rotate2);
         return rotate1;
       }

       private void connect(Canvas3D canvas3D,
                            BranchGroup scene) {
         SimpleUniverse simpleU =
                           new SimpleUniverse(canvas3D);
         simpleU.getViewingPlatform().
                           setNominalViewingTransform();
         simpleU.addBranchGraph(scene);
       }

       public static void main(String[] args) {
         new Spinning3DWorld().setVisible(true);
       }
    }

After you compile and run Spinning3DWorld, you should see the the same ColorCube that you displayed with the Static3DWorld program, but this time the cube should rotate. Here's a display captured at one instant in time:

java3d

Now for a final example. In this example, Text3DWorld, let's replace the the spinning ColorCube with three dimensional text. This adds a little complexity. The construction of the Text3D object requires a few more details than what you might be used to when working with Fonts. You have more options and could customize the shape in more ways by altering the texture or material of the Shape3D object. Here is a simple case that mainly uses the default values.

   private Shape3D createTextShape() {
        Appearance textAppear = new Appearance();
        textAppear.setMaterial(new Material());
        Font3D font3D = new Font3D(new Font("Helvetica",
                                         Font.PLAIN, 1),
                                   new FontExtrusion());
        Text3D textGeom = new Text3D(font3D,
                             new String("Text3DWorld"));
        textGeom.setAlignment(Text3D.ALIGN_CENTER);
        Shape3D textShape = new Shape3D();
        textShape.setGeometry(textGeom);
        textShape.setAppearance(textAppear);
        return textShape;
   }

The chief difference in this example as compared to the previous example is that you need to light the object. If you do not provide lighting, the spinning text will not be visible. You have three basic choices for lights: AmbientLight, DirectionalLight, and PointLight. This example uses DirectionalLight. You specify the direction of the light as a vector of floats. Similarly, you must specify the color using a red, green, blue triple of floats between 0 and 1. If you project more than one light source on an object the light values are summed but each color is clipped at 1.

     private void setLighting(TransformGroup objMove) {
       DirectionalLight light = 
                                new DirectionalLight();
       light.setInfluencingBounds(
                                 new BoundingSphere());
       light.setDirection(
                        new Vector3f(0.0f,0.0f,-1.0f));
       light.setColor(
                        new Color3f(0.0f1.0f1.0f));
       objMove.addChild(light);
   }

Here's the code for Text3DWorld:

    import com.sun.j3d.utils.universe.SimpleUniverse;
    import javax.media.j3d.BranchGroup;
    import javax.media.j3d.Transform3D;
    import javax.media.j3d.TransformGroup;
    import javax.media.j3d.Canvas3D;
    import javax.media.j3d.Alpha;
    import javax.media.j3d.RotationInterpolator;
    import javax.media.j3d.BoundingSphere;
    import javax.media.j3d.Appearance;
    import javax.media.j3d.Material;
    import javax.media.j3d.Font3D;
    import javax.media.j3d.FontExtrusion;
    import javax.media.j3d.Text3D;
    import javax.media.j3d.Shape3D;
    import javax.media.j3d.DirectionalLight;
    import javax.swing.JFrame;
    import javax.vecmath.Vector3f;
    import javax.vecmath.Color3f;
    import java.awt.BorderLayout;
    import java.awt.GraphicsConfiguration;
    import java.awt.Font;

    public class Text3DWorld extends JFrame {

       private Transform3D rotate1 = new Transform3D();
       private  Transform3D rotate2 = new Transform3D();

       public Text3DWorld() {
         super("Text3DWorld");
         Canvas3D canvas3D = createCanvas3D();
         BranchGroup scene = createSceneGraph();
         connect(canvas3D, scene);
       }

       private Canvas3D createCanvas3D() {
         setSize(300300);
         getContentPane().setLayout(new BorderLayout());
         GraphicsConfiguration config =
           SimpleUniverse.getPreferredConfiguration();
         Canvas3D canvas3D = new Canvas3D(config);
         setSize(300300);
         getContentPane().add(canvas3D);
         return canvas3D;
       }

       public BranchGroup createSceneGraph() {
         BranchGroup objRoot = new BranchGroup();
         TransformGroup mover = moveTextBack();
         TransformGroup spinner = createSpinner();
         objRoot.addChild(mover);
         mover.addChild(spinner);
         spinner.addChildcreateTextShape());
         spinner.addChild(makeSpin(spinner));
         setLighting(mover);
         return objRoot;
       }

       private TransformGroup createSpinner() {
         TransformGroup spinner = new TransformGroup();
         spinner.setCapability(TransformGroup.
                                 ALLOW_TRANSFORM_WRITE);
         return spinner;
       }

       private TransformGroup moveTextBack() {
         Transform3D transform3D = new Transform3D();
         transform3D.setTranslation(
                       new Vector3f(0.0f0.0f, -5.0f));
         return new TransformGroup(transform3D);
       }

       private Shape3D createTextShape() {
         Appearance textAppear = new Appearance();
         textAppear.setMaterial(new Material());
         Font3D font3D = new Font3D(
                  new Font("Helvetica", Font.PLAIN, 1),
                                   new FontExtrusion());
         Text3D textGeom = new Text3D(font3D,
                             new String("Text3DWorld"));
         textGeom.setAlignment(Text3D.ALIGN_CENTER);
         Shape3D textShape = new Shape3D();
         textShape.setGeometry(textGeom);
         textShape.setAppearance(textAppear);
         return textShape;
      }

       private void setLighting(
                               TransformGroup objMove) {
         DirectionalLight light =
                                 new DirectionalLight();
        light.setInfluencingBounds(
                                  new BoundingSphere());
        light.setDirection(
                         new Vector3f(0.0f,0.0f,-1.0f));
        light.setColor(new Color3f(
                                     0.0f1.0f1.0f));
        objMove.addChild(light);
       }

       private RotationInterpolator makeSpin(
                               TransformGroup spinner) {
         RotationInterpolator rotator =
           new RotationInterpolator(
                          new Alpha(-13000), spinner);
            rotator.setTransformAxis(rotateCube());
            BoundingSphere bounds =
                                   new BoundingSphere();
         rotator.setSchedulingBounds(bounds);
         return rotator;
       }

       private Transform3D rotateCube() {
         rotate1.rotX(Math.PI / 4.0d);
         rotate2.rotY(Math.PI / 3.0d);
         rotate1.mul(rotate2);
         return rotate1;
       }

       private void connect(Canvas3D canvas3D,
                            BranchGroup scene) {
         SimpleUniverse simpleU =
           new SimpleUniverse(canvas3D);
         simpleU.getViewingPlatform().
           setNominalViewingTransform();
         simpleU.addBranchGraph(scene);
       }

       public static void main(String[] args) {
         new Text3DWorld().setVisible(true);
       }
    }

After you compile and run Text3DWorld, you should see the the rotating text Text3DWorld. Here's a display captured at one instant in time:

java3d

The objective in this tip was to add complexity, a little at a time. In the first example, you created and displayed a three dimensional object. Then things got a little more complex in the second example, where you rotated the object and set it spinning. The third example added a little more complexity. In that example, you rotated an object that required lighting. By using small modular methods you can easily build much more complicated examples.

For more information about the Java 3D API, see the Java 3D API Tutorial.

Copyright (c) 2004-2005 Sun Microsystems, Inc.
All Rights Reserved.


 Related Tips

 
< Prev   Next >

Page 1 of 0 ( 0 comments )

You can share your information about this topic using the form below!

Please do not post your questions with this form! Thanks.


Name (required)


E-Mail (required)

Your email will not be displayed on the site - only to our administrator
Homepage(optional)



Comment Enable HTML code : Yes No



 
       
         
     
 
 
 
   
 
 
java bottom left
java bottom middle
java bottom right
RSS 0.91 FeedRSS 1.0 FeedRSS 2.0 FeedATOM FeedOPML Feed

Home - About Us - Privacy Policy
Copyright 2005 - 2008 www.java-tips.org
Java is a trademark of Sun Microsystems, Inc.