JavaBack to Basics in the Java 3D API

Back to Basics in the Java 3D API

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Java Programming Notes #1541


Preface

General

Scope of the series of tutorial lessons

In the earlier lesson titled “Understanding Lighting in the Java 3D API” (see Resources), I taught you about, and showed you examples of many of the important features of scene illumination in the Java 3D API. I also provided the source code for a complete Java 3D lighting simulator program that you can use to experiment with light in the Java 3D API. At the end of that tutorial, I stated “I will explain how the Java 3D lighting simulator program works in subsequent parts of this multi-part lesson.”

Upon reflection, I have decided that it would be impractical for me to attempt to explain the inner workings of that very complicated program without first explaining a large number of basic concepts involved in writing programs using the Java 3D API. Therefore, beginning with this lesson, my plan is to start with the basics and to publish a series of tutorial lessons in which I will work my way up to the general complexity exhibited by the program that I provided in the earlier lesson. This will be the first lesson in that series.

Compiling and running Java 3D programs

In order to compile and run programs using the Java 3D API, you will need to download and install the Java 3D API software. As of the date of this writing, version 1.5.0 was available for download.

In addition, you will need to download and install either Microsoft DirectX or OpenGL. All of the sample programs in this series of tutorials were developed and tested using Microsoft DirectX. They were not tested using OpenGL.

Acknowledgement

Most of what I will be teaching you about the use of the Java 3D API was learned by studying the tutorial by Dennis J Bouvier (see Resources) along with some other online material listed in Resources.

You can also download the Bouvier tutorial as a set of PDF files along with the source code for the example programs in his tutorial. I recommend that you take advantage of those resources as well.

Viewing tip

I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.

Figures

  • Figure 1. Bouvier’s recipe for using the SimpleUniverse class to create a Java 3D virtual universe.
  • Figure 2. Sun’s description of the SimpleUniverse class.
  • Figure 3. Description of one of the available constructors for the SimpleUniverse class.
  • Figure 4. Target Java 3D virtual universe for this lesson.
  • Figure 5. Virtual universe produced by program Java3D001.
  • Figure 6. Sun’s description of the Group class.
  • Figure 7. Sun’s description of the BranchGroup class.
  • Figure 8. Virtual universe produced by Program Java3D002.
  • Figure 9. One of two Canvas3D constructors.
  • Figure 10. Virtual universe from a future lesson.

Listings

Supplementary material

I recommend that you also study the other lessons in my extensive collection of online Java tutorials. You will find a consolidated index at www.DickBaldwin.com.

General background information

A Java 3D virtual universe

Obviously, programs that you create using the Java 3D API will have a strong visual component. We can refer to that visual component as a Java 3D virtual universe.

Listing 1. The program named Java3D001.

/*File Java3D001.java
Copyright 2007, R.G.Baldwin
Tested using Java SE 6, and Java 3D 1.5.0 running under
Windows XP.
**********************************************************/
import com.sun.j3d.utils.universe.SimpleUniverse;

public class Java3D001{

  public Java3D001(){//constructor
    SimpleUniverse universe = new SimpleUniverse(null);
    
    //The following constructor that doesn't explicitly
    // pass null as a parameter appears to produce exactly
    // the same result:
    // SimpleUniverse universe = new SimpleUniverse();
  }//end constructor

  public static void main(String[] args){
    new Java3D001();
  }//end main

}//end class Java3D001

Purpose of the program

Could be even simpler
This program could have been even simpler by calling the SimpleUniverse constructor that takes no parameters instead of passing a null parameter to the constructor. Both approaches appear to produce exactly the same result.

The purpose of this program is to illustrate an extremely simple Java 3D program. When this code is compiled and executed, an empty window appears on the screen as shown in Figure 5.

Figure 5. Virtual universe produced by program Java3D001.

Description of the window

The window shown in Figure 5 looks just like an AWT Frame object with:

  • A Color.BLACK background
  • An empty title bar
  • A size of 255×255 pixels

The BranchGroup object

Next, the code in Listing 2 instantiates a new BranchGroup node object and populates it with a reference to a single visual object of the class ColorCube.

A ColorCube object

Sun describes a ColorCube object as a “Simple color-per-vertex cube with a different color for each face.” There are two constructors for the ColorCube class. One of the constructors constructs a cube with its center at the origin and a default size.If I interpreted the description of that constructor correctly, the default length of any edge is two units (from -1 to 1).

The other constructor, which is the one used in Listing 2, also constructs a cube with its center at the origin in 3D space. This constructor allows the programmer to specify the size of the cube, by providing a float value for the parameter named scale.

Once again, if I interpreted the description of that constructor correctly, the length of any edge of the cube is twice the value of scale. Thus, the length of each edge for the cube constructed in Listing 2 would be 0.4 units (from -0.2 to 0.2). To a first degree of approximation, given what we learnedabove, the length of each edge of the cube shown in Figure 8 should be a little more than twenty-percent of the size of the window. Once again, keep in mind that the visible face on the cube is between the viewer’s eye and the origin in 3D space so it will appear to be larger than would be the case if that face were located at the origin.

Call the addBranchGraph method on the universe

Here is part of what Sun has to say about the method named addBranchGraph:

“Used to add Nodes to the geometry side (as opposed to the view side) of the scene graph. This is a short cut to getting the Locale object and calling that object’s addBranchGraph() method.”

Thus, the last statement in the constructor in Listing 2 adds the BranchGroup object containing the visual ColorCube object to the universe, making the cube visible in Figure 8.

Satisfies the recipe

The code shown in Listing 2 satisfies all of the steps specified in the recipe shown in Figure 1 with the exception of the fourth step having to do with compiling the content branch. This is a fairly complicated topic, but that step effectively happens automatically in the code in Listing 2. I will have more to say on this topic in future lessons.

While there is much more to learn in order to effectively use the Java 3D API, at least at this point you know some of the fundamentals. You have seen a program that satisfies all of the steps required in the recipe in Figure 1.

There is still a problem

However, there is a problem that we have not yet addressed.  As I mentioned earlier, when this approach is used to create the 3D universe, the programmer has no control over the size of the window and has no way to put a title into the title bar. In some cases that may be a problem and in other cases it may not be a problem. In any event, this situation is not hard to resolve. That will be the purpose of the next sample program.

The program named Java3D003

Because of its length, I will present and discuss this program in fragments. The program named Java3D003 begins in Listing 3. A complete listing of the program is provided in Listing 10 for your convenience.

Purpose

The purpose of this program is to illustrate how to extend the Frame class and use a Canvas3D object to gain control over the size and title bar of a Java 3D application. The program also illustrates how to gain control over the layout of the Frame containing the universe along with other components that may also appear in the Frame.

Screen output

The screen output for this program is shown in Figure 4. When this program is compiled and executed, a Frame object appears on the screen with a black Canvas3D object containing the virtual universe in the CENTER location of the Frame. The universe contains a visual ColorCube object.

Label objects appear in the NORTH and SOUTH locations of the Frame.

When the user resizes the Frame, the size of the ColorCube object changes in proportion to the size of the Canvas3D object.

When the user clicks the close button in the upper-right corner of the Frame, the program terminates.

Program code

Listing 3. Beginning of the program named Java3D003.

public class Java3D003 extends Frame{

  public Java3D003(){//constructor
    setLayout(new BorderLayout());

    //Create a Canvas3D object to be used for rendering the
    // Java 3D universe.  Place it in the CENTER of the
    // Frame.
    Canvas3D canvas = new Canvas3D(
               SimpleUniverse.getPreferredConfiguration());

    add(BorderLayout.CENTER,canvas);

Listing 3 performs the following operations:

  • Sets the layout for the Frame.
  • Instantiates a Canvas3D object.
  • Adds the canvas object to the Frame.

Of the three operations, only the second one deserves any further discussion at this point.

A Canvas3D object

The Sun documentation provides a long and detailed description of the various aspects of a Canvas3D object. I won’t repeat that information here, but will recommend that you study the description in the Sun documentation carefully.

Constructors for the Canvas3D class

Version 1.5.0 of the Java 3D API provides two constructors for the Canvas3D class. They differ primarily in terms of whether the rendering is performed on-screen or off-screen. The version used in this program is the on-screen rendering version. Figure 9 tells us some of what Sun has to say about this constructor.

Figure 9. One of two Canvas3D constructors.

Canvas3D

public Canvas3D(java.awt.GraphicsConfiguration graphicsConfiguration)

Constructs and initializes a new Canvas3D object that Java 3D can render into. The following Canvas3D attributes are initialized to default values as shown:

    left manual eye in image plate : (0.142, 0.135, 0.4572)
    right manual eye in image plate : (0.208, 0.135, 0.4572)
    stereo enable : true
    double buffer enable : true
    monoscopic view policy : View.CYCLOPEAN_EYE_VIEW
    off-screen mode : false
    off-screen buffer : null
    off-screen location : (0,0)
Parameters:
graphicsConfiguration – a valid GraphicsConfiguration object that will be used to create the canvas. This object should not be null and should be created using a GraphicsConfigTemplate3D or the getPreferredConfiguration() method of the SimpleUniverse utility. For backward compatibility with earlier versions of Java 3D, a null or default GraphicsConfiguration will still work when used to create a Canvas3D on the default screen, but an error message will be printed. A NullPointerException or IllegalArgumentException will be thrown in a subsequent release.
Throws:
java.lang.IllegalArgumentException – if the specified GraphicsConfiguration does not support 3D rendering

Could be difficult to construct

Here is an excerpt from the java.awt.GraphicsConfiguration class description:

“The GraphicsConfiguration class describes the characteristics of a graphics destination such as a printer or monitor. There can be many GraphicsConfiguration objects associated with a single graphics device, representing different drawing modes or capabilities. The corresponding native structure will vary from platform to platform.”

As you might surmise from Figure 9 and the above quotation, it could be fairly difficult to construct the GraphicsConfiguration object required as a parameter for any specific platform. Fortunately, the SimpleUniverse class provides a static convenience method named getPreferredConfiguration that eliminates the requirement for us to explicitly construct that object. The Sun documentation states that the invocation of this method will find and return “The best GraphicsConfiguration object for the system.” That convenience method is called to construct the new Canvas3D object in Listing 3.

Two placeholder objects

Listing 4 creates a pair of Label objects to serve as placeholders. These objects are positioned in the NORTH and SOUTH locations of the Frame to illustrate control over the layout of the Frame containing the virtual universe.

Listing 4. Two placeholder objects.

    add(BorderLayout.NORTH,new Label(
                        "Label object in NORTH location"));
    add(BorderLayout.SOUTH, new Label(
                        "Label object in SOUTH location"));

Create empty Java 3D universe

Listing 5 creates an empty Java 3D universe and associates it with the Canvas3D object in the CENTER of the Frame.

Listing 5. Create empty Java 3D universe.

    SimpleUniverse universe = new SimpleUniverse(canvas);

Note that the constructor used in Listing 5 is different from the constructor used in Listings 1 and 2. In the two previous cases, a null parameter was passed to the constructor for the SimpleUniverse object and the required Canvas3D object was automatically created. In Listing 5, a reference to an existing Canvas3D object was passed to the SimpleUniverse constructor in order to associate the new universe with the existing Canvas3D object.

Same code as before

The code in Listing 6 is essentially the same code as I explained in conjunction with Listing 2.  Therefore, I won’t repeat that explanation.

Listing 6. Same code as before.

    //Set the apparent position of the viewer's eye.
    universe.getViewingPlatform().
                              setNominalViewingTransform();

    //Put a visible object in the universe
    BranchGroup branchGroup = new BranchGroup();
    branchGroup.addChild(new ColorCube(0.2));

    universe.addBranchGraph(branchGroup);

Legacy code from earlier tutorials

The code in Listing 7 is the same as code that I have used and explained in dozens (possibly hundreds) of earlier tutorials. Therefore, it shouldn’t require any further explanation.

Listing 7. Legacy code from earlier tutorials.

    //Set the Frame size and title and make it all visible.
    setSize(475,475);
    setTitle("Copyright 2007, R.G.Baldwin");
    setVisible(true);
    
    //This listener is used to terminate the program when
    // the user clicks the X in the upper-right corner of
    // the Frame.
    addWindowListener(
      new WindowAdapter(){
        public void windowClosing(WindowEvent e){
          System.exit(0);
        }//end windowClosing
      }//end new WindowAdapter
    );//end addWindowListener
  }//end constructor
  //-----------------------------------------------------//

  public static void main(String[] args){
    Java3D003 thisObj = new Java3D003();
  }//end main
  //-----------------------------------------------------//

}//end class Java3D003

Listing 7 contains the end of the class and the end of the program. In addition, it is almost the end of the lesson.

Run the programs

I encourage you to copy the code from Listings 8 through 10 into your text editor, compile it, and execute it. Experiment with it, making changes, and observing the results of your changes. Remember, you will need to download and install the Java 3D API plus either Microsoft DirectX or OpenGL to compile and execute these programs. See Downloads for links to the web sites from which this material can be downloaded.

Summary

In this lesson, I taught you to master the basics of starting from scratch to create and populate a Java 3D virtual universe, and how to place that universe in a Frame along with other GUI components using the layout manager of your choice. While the results shown in Figure 4 don’t look that impressive, they are critically important in your progress down the path of learning how to effectively use the Java 3D API.

What’s next?

The material covered in this lesson is just the tip of the Java 3D iceberg. There is much more for you to learn if you want to make effective use of the Java 3D API.

In the next lesson, I will teach you how to write a Java 3D program to create and populate a virtual universe that looks similar to the one shown in Figure 10.

Figure 10. Virtual universe from a future lesson.

As a minimum, I will use this program to teach you how to use the following Java 3D classes along with various methods belonging to those classes:

  • SimpleUniverse
  • Sphere
  • Primitive
  • Appearance
  • Material
  • PointLight
  • BranchGroup
  • Canvas3D
  • Transform3D
  • TransformGroup
  • BoundingSphere
  • Vector3f
  • Point3f
  • Point3d
  • Color3f

Downloads

Resources

Complete program listings

Complete listings of the programs discussed in this lesson are shown in Listing 8 through Listing 10 below.

Listing 8. Listing for program Java3D001.

/*File Java3D001.java
Copyright 2007, R.G.Baldwin

The purpose of this program is to illustrate an extremely 
simple Java 3D program.

When this code is compiled and executed, an empty window
appears on the screen.  The window looks just like an
AWT Frame object with a Color.BLACK background, an empty
title bar, and a size of 255x255 pixels.

Clicking the close button in the upper-right corner of the
window causes the program to terminate, even though the
program does not register a WindowListener object on the
frame.

As near as I have been able to determine, when this
approach is used to create the 3D universe, the programmer
has no control over the size of the window and has no way
to put a title into the title bar.  Note however, that the
window is resizable, meaning that the size can be changed
by the user dragging the corners of the window.

Tested using Java SE 6, and Java 3D 1.5.0 running under
Windows XP.
**********************************************************/
import com.sun.j3d.utils.universe.SimpleUniverse;

public class Java3D001{

  public Java3D001(){//constructor
    SimpleUniverse universe = new SimpleUniverse(null);

    //The following constructor that doesn't explicitly
    // pass null as a parameter appears to produce exactly
    // the same result:
    // SimpleUniverse universe = new SimpleUniverse();
  }//end constructor

  public static void main(String[] args){
    new Java3D001();
  }//end main

}//end class Java3D001

 

Listing 9. Listing for program Java3D002.

/*File Java3D002.java
Copyright 2007, R.G.Baldwin

The purpose of this program is to update Java3D001 to add 
an object to the virtual universe while keeping the 
program as simple as possible.

When this code is compiled and executed, a window appears
on the screen the same as in the Java3D001.  However, the
window is no longer empty.  Instead, it contains a red
square.  The red square is actually one face of a 3D cube
with colored faces.

Tested using Java SE 6, and Java 3D 1.5.0 running under
Windows XP.
**********************************************************/
import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.geometry.ColorCube;
import javax.media.j3d.BranchGroup;

public class Java3D002{

  public Java3D002(){//constructor
    SimpleUniverse universe = new SimpleUniverse(null);
    
    universe.getViewingPlatform().
                              setNominalViewingTransform();

    BranchGroup branchGroup = new BranchGroup();
    branchGroup.addChild(new ColorCube(0.2));

    universe.addBranchGraph(branchGroup);
  }//end constructor

  public static void main(String[] args){
    new Java3D002();
  }//end main

}//end class Java3D002

 

Listing 10. Listing for program Java3D003.

/*File Java3D003.java
Copyright 2007, R.G.Baldwin

The purpose of this program is to illustrate how to 
extend the Frame class and use a Canvas3D object to 
gain control over the size and title bar of a Java 3D 
application.  It also illustrates how to gain control over
the layout of the universe in conjunction with other 
components that may also appear in the Frame along with
the universe.

When this code is compiled and executed, a Frame object
appears on the screen with a black Canvas3D object 
containing the virtual universe in the CENTER location of 
the Frame.  The universe contains a visual ColorCube 
object.  Labels appear in the NORTH and SOUTH locations of
the Frame.

When the user resizes the Frame, the size of the ColorCube
object changes in proportion to the size of the Canvas3D
object.

When the user clicks the close button in the upper-right
corner of the Frame, the program terminates.

Tested using Java SE 6, and Java 3D 1.5.0 running under
Windows XP.
**********************************************************/
import com.sun.j3d.utils.universe.SimpleUniverse;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.BranchGroup;
import com.sun.j3d.utils.geometry.ColorCube;
import java.awt.Frame;
import java.awt.Label;
import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class Java3D003 extends Frame{

  public Java3D003(){//constructor
    setLayout(new BorderLayout());

    //Create a Canvas3D object to be used for rendering the
    // Java 3D universe.  Place it in the CENTER of the
    // Frame.
    Canvas3D canvas = new Canvas3D(
               SimpleUniverse.getPreferredConfiguration());
    add(BorderLayout.CENTER,canvas);

    //Create a pair of Label objects to serve as
    // placeholders.  Position them in the NORTH and SOUTH
    // locations in the window.
    add(BorderLayout.NORTH,new Label(
                        "Label object in NORTH location"));
    add(BorderLayout.SOUTH, new Label(
                        "Label object in SOUTH location"));

    //Create an empty Java 3D universe and associate it 
    // with the Canvas3D object in the CENTER of the
    // Frame.
    SimpleUniverse universe = new SimpleUniverse(canvas);

    //Set the apparent position of the viewer's eye.
    universe.getViewingPlatform().
                              setNominalViewingTransform();

    //Put a visible object in the universe
    BranchGroup branchGroup = new BranchGroup();
    branchGroup.addChild(new ColorCube(0.2));

    universe.addBranchGraph(branchGroup);

    //Set the Frame size and title and make it all visible.
    setSize(475,475);
    setTitle("Copyright 2007, R.G.Baldwin");
    setVisible(true);

    //This listener is used to terminate the program when
    // the user clicks the X in the upper-right corner of
    // the Frame.
    addWindowListener(
      new WindowAdapter(){
        public void windowClosing(WindowEvent e){
          System.exit(0);
        }//end windowClosing
      }//end new WindowAdapter
    );//end addWindowListener
  }//end constructor
  //-----------------------------------------------------//

  public static void main(String[] args){
    Java3D003 thisObj = new Java3D003();
  }//end main
  //-----------------------------------------------------//

}//end class Java3D003

Copyright

Copyright 2007, Richard G. Baldwin. Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas. He is the author of Baldwin’s Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP). His first job after he earned his Bachelor’s degree was doing DSP in the Seismic Research Department of Texas Instruments. (TI is still a world leader in DSP.) In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

Baldwin@DickBaldwin.com

-end-

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories