JavaDigging a Little Deeper into the Java 3D API

Digging a Little Deeper into 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 # 1542


Preface

General

Scope of this 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 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, I decided to publish a series of lessons that would start with the basics and work up to the general complexity exhibited by the program that I provided in the lesson titled “Understanding Lighting in the Java 3D API”. The first lesson in that new series was titled “Back to Basics in the Java 3D API” (see Resources). This is the second lesson in the new 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 is 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 other online material, some of which is listed in Resources.

You can view the Bouvier tutorial online. 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. The target virtual universe for this lesson.

Listings

  • Listing 1. A top-level driver class.
  • Listing 2. Beginning of the class named TheScene.
  • Listing 3. Set a Material object to yellow for diffuse light.
  • Listing 4. Set appearance for the yellow sphere.
  • Listing 5. Create the large yellow sphere.
  • Listing 6. Create the small white sphere.
  • Listing 7. Translate the white sphere.
  • Listing 8. Create and translate the small green sphere.
  • Listing 9. Add a white PointLight object to the scene.
  • Listing 10. Specify which objects to illuminate.
  • Listing 11. Create and populate the 3D universe.
  • Listing 12. The end of the program.
  • Listing 13. Listing of the program named Java3D004.

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.

Preview

In the previous lesson titled “Back to Basics in the Java 3D API” (see Resources), I taught you to master the basics of starting from scratch to create and populate a Java 3D virtual universe. I also taught you how to place that universe in a Frame along with other GUI components using the layout manager of your choice. While the visual results produced in that lesson didn’t look too impressive, an understanding of the steps required to produce those results is critically important to your progress down the path of learning how to effectively use the Java 3D API.

Just the tip of the iceberg

The material covered in that 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 this lesson, I will teach you how to write a Java 3D program to create, populate, and display the virtual universe shown on the left side of Figure 1.

Figure 1. The target virtual universe for this lesson.

A long list of new classes

I will use the program to teach you how to use the following Java 3D classes (that were not covered in the previous lesson) along with various methods belonging to those classes:

  • com.sun.j3d.utils.geometry.Sphere
  • com.sun.j3d.utils.geometry.Primitive
  • javax.media.j3d.Appearance
  • javax.media.j3d.Material
  • javax.media.j3d.PointLight
  • javax.media.j3d.Transform3D
  • javax.media.j3d.TransformGroup
  • javax.media.j3d.BoundingSphere
  • javax.vecmath.Vector3f
  • javax.vecmath.Point3f
  • javax.vecmath.Point3d
  • javax.vecmath.Color3f

Discussion and sample code

In this lesson, I will explain the program named Java3D004, which is presented in Listing 13. As is my custom with long programs, I will explain the program in fragments. The first fragment is shown in Listing 1.

A top-level driver class

Listing 1 contains a top-level driver class for the program. This program could have been written without the use of this driver class. However, I decided to keep it intact for future expansions that require a user input GUI.

Listing 1. A top-level driver class.

public class Java3D004 extends Frame{
  public static void main(String[] args){
    Java3D004 thisObj = new Java3D004();
  }//end main
  //----------------------------------------------------//
  
  public Java3D004(){//constructor
    setTitle("Copyright 2007, R.G.Baldwin");
    add(new Label("You can build a GUI here."));
    setBounds(236,0,235,75);
    setVisible(true);
    
    //Instantiate the object in which the Java 3D
    // universe will be displayed.
    TheScene theScene = new TheScene();

    //This window listener is used to terminate the
    // program when the user clicks the X button.
    addWindowListener(
      new WindowAdapter(){
        public void windowClosing(WindowEvent e){
          System.exit(0);
        }//end windowClosing
      }//end new WindowAdapter
    );//end addWindowListener

  }//end constructor

The user input GUI

The user input GUI produced by Listing 1 is shown in the right side of Figure 1. Except for the X-button in the upper right corner of the Frame that can be used to terminate the program, the GUI is of no use in this program. Note however that the code in Listing 1 does instantiate a new object of the class named TheScene. This causes the 3D universe shown in the left side of Figure 1 to be created and displayed.

Beginning of the class named TheScene

Listing 2 shows the beginning of the class named TheScene, which is an inner class that extends the Frame class.

Listing 2. Beginning of the class named TheScene.

  class TheScene extends Frame{

    TheScene(){//constructor

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

The code in Listing 2 is essentially the same as code that I explained in the previous lesson so I won’t repeat that explanation here.

Construct and set properties for the large yellow sphere

Listing 3 begins the construction of the objects that will be displayed in the scene as well as the other objects necessary to support those objects. This code begins by creating and setting properties for the large yellow sphere.

Listing 3. Set a Material object to yellow for diffuse light.

      Material yellowSphMaterial = new Material();
      yellowSphMaterial.setDiffuseColor(1.0f,1.0f,0.0f);

Listing 3 begins the code required to establish the appearance of the large yellow sphere shown in Figure 1.

What is a Material object?

According to the Sun documentation, a Material object defines the appearance (color) of an object under illumination. In other words, a Material object defines what the object will look like when it is illuminated by one or more of the various light sources that are available in the Java 3D API.

Properties of the Material class

Several properties can be set for a Material object, including the color that will appear when the object is illuminated by one or more of the following types of light sources:

  • Ambient
  • Diffuse
  • Specular
  • Emissive

In addition, a property can be set to define the material’s shininess, in the range from 1.0 to 128.0 with 1.0 being not shiny and 128.0 being very shiny.

I explained a great deal about the effect of illumination on 3D objects in the earlier lesson titled “Understanding Lighting in the Java 3D API” (see Resources). Therefore, I will refer you to that lesson for further information on this topic.

The code in Listing 3 sets the Material object so that it will cause the sphere to appear to be yellow when illuminated by a PointLight source later.

Set appearance for the yellow sphere

All that we have done so far is to create a Material object with certain properties. We haven’t connected that Material object to the sphere yet.

Listing 4 creates an Appearance object that will be used connect the Material object to the sphere.

Listing 4. Set appearance for the yellow sphere.

      Appearance yellowSphAppearance = new Appearance();
      yellowSphAppearance.setMaterial(yellowSphMaterial);

What is an Appearance object?

According to the Sun documentation, an Appearance object “defines all rendering state that can be set as a component object of a Shape3D node.” The rendering state consists of the following:

  • Coloring attributes
  • Line attributes
  • Point attributes
  • Polygon attributes
  • Rendering attributes
  • Transparency attributes
  • Material
  • Texture
  • Texture attributes
  • Texture coordinate generation
  • Texture unit state

In other words, you can set properties on an Appearance object to control all of the attributes in the above list when an object connected to the appearance is rendered on the screen. In this case, we are concerned only with the Material property. Listing 4 sets the Material property by calling the setMaterial method on a new Appearance object passing a reference to the existing Material object as a parameter.

Create the large yellow sphere

Listing 5 instantiates a Sphere object by calling a constructor which, according to the Sun documentation, requires the following four parameters of the types given:

  • float radius
  • int primitiveFlags
  • int divisions
  • Appearance appearance

This sphere is instantiated with a radius of 0.5. A reference to the Appearance object created above is passed as the fourth parameter.

Listing 5. Create the large yellow sphere.

      Sphere yellowSph = new Sphere(
                               0.5f,
                               Primitive.GENERATE_NORMALS,
                               9,
                               yellowSphAppearance);

What are the divisions?

As I understand it, the value for divisions is the number of flat surfaces that would be encountered in making one trip around the equator of the sphere. The larger you make this value, the closer your sphere will approximate a true sphere. (For example, if you set this value to 4, you would end up with a cube instead of a sphere.)

The yellow sphere shown in Figure 1 was created with nine divisions. As you can see, it isn’t a very good approximation of a true sphere due to the low number of divisions. On the other hand, the small white and green spheres are good approximations of true spheres because they were each instantiated with 50 divisions. I also discussed this topic in the earlier lesson titled “Understanding Lighting in the Java 3D API” (see Resources).

What about Primitive.GENERATE_NORMALS?

That is a good question. I believe that this parameter has something to do with the ability of the system to render the object on the screen. The Sun documentation simply states that this value “Specifies that normals are generated along with the positions.”

Apparently there are other possible values for this parameter as well. I searched the web in an attempt to find a more informative explanation. Most web sites that discuss Java 3D are simply silent on this topic. Among those that aren’t silent, I didn’t find anything that was very informative. At this point, the best that I can tell you is simply to define this parameter as shown in Listing 5. For example, if you pass Primitive.GENERATE_NORMALS_INWARD instead of Primitive.GENERATE_NORMALS as the second parameter to the constructor, you will get a white sphere with no shading.

Create the small white sphere

Listing 6 creates the white sphere in the foreground of Figure 1 with a radius of 0.1.  The sphere is created with 50 divisions so that it will be a good approximation of a true sphere.

Listing 6. Create the small white sphere.

      Material whiteSphMaterial = new Material();
      whiteSphMaterial.setDiffuseColor(1.0f,1.0f,1.0f);
      Appearance whiteSphAppearance = new Appearance();
      whiteSphAppearance.setMaterial(whiteSphMaterial);
      Sphere whiteSph = new Sphere(
                               0.10f,
                               Primitive.GENERATE_NORMALS,
                               50,
                               whiteSphAppearance);

When the code in Listing 6 has been executed, the sphere is still located at the origin in 3D space. It must be translated in 3D space in order to cause it to appear as shown in Figure 1.

Translate the white sphere

The code in Listing 7 may be the most difficult code in the entire program to understand. Unless you already understand quite a bit about matrix arithmetic, you probably won’t be able to understand it completely. Fortunately, you don’t have to understand all of the inner workings of the code in order to be able to use it. You simply have to understand the procedures involved.

Listing 7. Translate the white sphere.

      Transform3D whiteTransform = new Transform3D();
      whiteTransform.setTranslation(
                          new Vector3f(-0.5f,-0.5f,0.5f));
                          
      TransformGroup whiteTransformGroup = 
                                     new TransformGroup();
      whiteTransformGroup.setTransform(whiteTransform);
      whiteTransformGroup.addChild(whiteSph);

The code in Listing 7 creates and populates the objects necessary to translate the location of the white sphere to make it appear to be closer to the viewer than the yellow sphere at the origin. The white sphere is also moved down and to the left.

Instantiate a Transform3D object

I taught you a little about transformations in 2D space in the earlier lesson titled “Java 2D Graphics, Simple Affine Transforms” (see Resources).It might be helpful for you to refer back to that lesson in order to better understand what is going on here in 3D space.

An object of the Transform3D class

Listing 7 begins by instantiating a new object of the class Transform3D. According to Sun, a Transform3D object is:

“A generalized transform object represented internally as a 4×4 double-precision floating point matrix. … A Transform3D is used to perform translations, rotations, and scaling and shear effects.”

Among the many methods of the Transform3D class are various overloaded versions of the following methods:

  • setScale(double scale)
  • setTranslation(Vector3f trans)
  • setRotation(Matrix3d m1)

To make a long story short, a general Transform3D object can be converted into an object that is useful for scaling, translating, or rotating an object in 3D space by calling one of these methods on the Transform3D object.

Create and prepare the Transform3D object

Listing 7 begins by creating a Transform3D object. Then it calls the setTranslation method on that object passing a reference to a Vector3f object as a parameter. This converts the transform object to one that can be used to translate an object in 3D space by -0.5 units along the x-axis, -0.5 units along the y-axis, and +0.5 units along the z-axis. This has the effect of moving the object to the left, down, and toward the viewer as shown by the white sphere in Figure 1.

What is a Vector3f object?

According to Sun, a Vector3f object is “A 3-element vector that is represented by single-precision floating point x,y,z coordinates.”

Similarly, a Vector3d object is “A 3-element vector that is represented by double-precision floating point x,y,z coordinates.”

A vector is normally thought of something that has length and direction. There are several ways to represent a vector. In the two cases above, the vector is represented by three floating point values.

In this program, a Vector3f object is used to condition the Transform3D object so that it can be used to move an object by a specified distance in a specified direction.

What is a TransformGroup?

Recall from the previous lesson that a Group object is an object that can encapsulate references to one or more child objects. A BranchGroup object extends the Group class and can be used to encapsulate references to one or more objects. The BranchGroup object can later be added to the universe, and the visual objects encapsulated in the BranchGroup object will be rendered in the 3D virtual universe.

The TransformGroup class also extends the Group class. A TransformGroup object contains a reference to a Transform3D object in addition to references to one or more child objects.

Can be added to a BranchGroup object

A TransformGroup object can also be added to a BranchGroup object in addition to the ordinary objects that are added to the BranchGroup object. Then, when the scene is rendered, the transform specified by the Transform3D object will be applied to all of the children encapsulated in the TransformGroup object.

The third statement in Listing 7 instantiates a new TransformGroup object. The fourth statement adds the Transform3D object created earlier to the group. The fifth statement causes the white sphere to be a child of the TransformGroup object. This will cause the specified translation to be applied to the white sphere when the scene is rendered, moving the sphere away from the origin down, to the left, and closer to the viewer from the viewer’s viewpoint. Hence, the small white sphere in Figure 1 appears down, to the left, and closer to the viewer than the yellow sphere, (which is centered at the origin in 3D space.).

Create and translate the small green sphere

Listing 8 uses similar code to create a small green sphere located up, to the right, and behind the yellow sphere.

Listing 8. Create and translate the small green sphere.

      Material greenSphMaterial = new Material();
      greenSphMaterial.setDiffuseColor(0.0f,1.0f,0.0f);
      Appearance greenSphAppearance = new Appearance();
      greenSphAppearance.setMaterial(greenSphMaterial);
      Sphere greenSph = new Sphere(
                               0.10f,
                               Primitive.GENERATE_NORMALS,
                               50,
                               greenSphAppearance);
      Transform3D greenTransform = new Transform3D();
      greenTransform.setTranslation(
                           new Vector3f(0.5f,0.5f,-0.5f));
      TransformGroup greenTransformGroup = 
                                     new TransformGroup();
      greenTransformGroup.setTransform(greenTransform);
      greenTransformGroup.addChild(greenSph);

Add a white PointLight object to the scene

Listing 9 adds a white PointLight, in front of, to the right of, and above the yellow sphere. As you can see in Figure 1, this causes the strongest illumination area of all three spheres to be to the right of and above the center point on the sphere from the viewpoint of the viewer. It also causes a shadow on the lower left portion of all three spheres.

Listing 9. Add a white PointLight object to the scene.

      Color3f pointLightColor = 
                              new Color3f(1.0f,1.0f,1.0f);
      Point3f pointLightPosition = 
                              new Point3f(1.0f,1.0f,2.0f);
      Point3f pointLightAttenuation = 
                              new Point3f(1.0f,0.0f,0.0f);
      
      PointLight pointLight = new PointLight(
                                   pointLightColor,
                                   pointLightPosition,
                                   pointLightAttenuation);

The code in Listing 9 creates objects for color, position, and attenuation of the PointLight source and passes those three objects to the constructor for the PointLight object.

What is a PointLight object?

Java 3D provides several different forms of illumination. You can learn quite a lot about this in my earlier lesson titled “Understanding Lighting in the Java 3D API” (see Resources).

According to Sun,

“The PointLight object specifies an attenuated light source at a fixed point in space that radiates light equally in all directions away from the light source.”

Saying that the light is attenuated means that the intensity of the light decreases with distance from the source. There are several ways that the attenuation characteristics can be specified for a PointLight source. I will leave it up to you to study and understand those different ways based on my earlier lesson and the Sun documentation.

What is a Color3f object?

According to Sun, a Color3f object encapsulates

“A three-element color value represented by single precision floating point x,y,z values. The x,y,z values represent the red, green, and blue color values, respectively. Color components should be in the range of [0.0, 1.0].”

In the case of Listing 9, all three color values are set to 1.0 causing the color of the light to be white.

What is a Point3f object?

When used to establish the light position as in Listing 9, a Point3f object encapsulates a 3-element point in space that is represented by single precision floating point x,y,z coordinates.

In Listing 9, the Point3f object is used to represent a location for the light source that is one unit to the right of, one unit above, and two units in front of the origin in 3D space.

Listing 9 also uses a Point3f object to specify the manner in which the intensity of the light will be attenuated relative to distance from the source.

Instantiate the PointLight object

The last statement in Listing 9 instantiates the PointLight object by passing references to the three objects discussed above to the PointLight constructor.

Specify which objects to illuminate

Listing 10 creates a BoundingSphere object and uses it to specify which objects will be illuminated by the PointLight source.

Listing 10. Specify which objects to illuminate.

      BoundingSphere boundingSphere = 
        new BoundingSphere(new Point3d(0.0,0.0,0.0), 1.0);
      pointLight.setInfluencingBounds(boundingSphere);

What is a BoundingSphere object?

According to Sun,

“This class defines a spherical bounding region which is defined by a center point and a radius.”

The setInfluencingBounds method

According to Bouvier,

“In Java 3D, the portion of a scene where visual objects are illuminated by a particular light source is called that light object’s region of influence. The simplest region of influence for a light source uses a Bounds object and the setInfluencingBounds() method of the light. When a light source object’s influencing bounds intersects the bounds of a visual object, the light is used in shading the entire object. The influencing bounds of a light determines which objects to light, not which portions of objects to light.”

Listing 10 sets the center of the BoundingSphere object to the origin and sets the radius to 1.0. (This bounding sphere includes all three spheres in the virtual universe.) The setInfluencingBounds method is called on the PointLight object, passing a reference to the BoundingSphere object as a parameter. Thus, all three spheres are illuminated in Figure 1.

Try this illumination experiment

If you modify the code in Listing 10 to move the center of the BoundingSphere to the location of the PointLight object, and change the radius to a value of 2.45, then only the white and yellow spheres will be included in the BoundingSphere. In that case, the green sphere will not be illuminated.

Create and populate the 3D universe

Listing 11 begins by creating an empty Java 3D universe and associating it with the
Canvas3D object in the CENTER of the frame.

Then Listing 11 creates a BranchGroup object and adds the light and
the yellow sphere to it.

Listing 11. Create and populate the 3D universe.

      SimpleUniverse simpleUniverse = 
                             new SimpleUniverse(canvas3D);
      
      //Create and populate a BranchGroup object.
      BranchGroup branchGroup = new BranchGroup();
      //Add objects to the branchGroup
      branchGroup.addChild(pointLight);
      branchGroup.addChild(yellowSph);
      //Note that adding the transform groups also adds
      // the objects contained in those groups.
      branchGroup.addChild(whiteTransformGroup);
      branchGroup.addChild(greenTransformGroup);
      
      //Specify the apparent location of the viewer's eye.
      simpleUniverse.getViewingPlatform().
                             setNominalViewingTransform();

      //Populate the universe by adding the branch group
      // that contains the objects.
      simpleUniverse.addBranchGraph(branchGroup);

Nothing new so far

Down to this point, there is nothing new in Listing 11. This code is essentially the same as the code that I explained in the previous lesson titled “Back to Basics in the Java 3D API” (see Resources)

The next two statements (highlighted in boldface) in Listing 11 are new to this lesson. Recall that I told you earlier that a TransformGroup object can also be added to a BranchGroup object along with the ordinary objects that are added to the BranchGroup object. This is where that happens. Listing 11 adds the whiteTransformGroup and greenTransformGroup objects to the BranchGroup object in addition to the yellow sphere and the light. Then when the scene is rendered, the white sphere and the green sphere will be translated according to the Transform3D objects encapsulated in those two groups.

The remaining code in Listing 11 is essentially the same as the code that I explained in the previous lesson.

The end of the program

The remaining program code is shown in Listing 12.

Listing 12. The end of the program.

      //Do the normal GUI stuff.
      setTitle("Copyright 2007, R.G.Baldwin");
      setBounds(0,0,235,235);
      setVisible(true);
      
      //This listener is used to terminate the program 
      // when the user clicks the X-button on the Frame.
      addWindowListener(
        new WindowAdapter(){
          public void windowClosing(WindowEvent e){
            System.exit(0);
          }//end windowClosing
        }//end new WindowAdapter
      );//end addWindowListener
      
    }//end constructor
    //--------------------------------------------------//
    
  }//end inner class TheScene

}//end class Java3D004

Listing 12 takes care of some normal GUI stuff, and signals the end of the program. There is nothing in Listing 12 that is new to this lesson. Therefore, further explanation won’t be necessary.

Run the program

I encourage you to copy the code from Listing 13 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 presented and explained a Java 3D program that illustrate many of the features of Java 3D. I used the program to teach you how to use the following Java 3D classes (that were not covered in the previous lesson) along with various methods belonging to those classes:

  • com.sun.j3d.utils.geometry.Sphere
  • com.sun.j3d.utils.geometry.Primitive
  • javax.media.j3d.Appearance
  • javax.media.j3d.Material
  • javax.media.j3d.PointLight
  • javax.media.j3d.Transform3D
  • javax.media.j3d.TransformGroup
  • javax.media.j3d.BoundingSphere
  • javax.vecmath.Vector3f
  • javax.vecmath.Point3f
  • javax.vecmath.Point3d
  • javax.vecmath.Color3f

What’s next?

The topic for the next lesson in this series will be simple animation in Java 3D.

Download

Resources

Complete program listing

A complete listing of the program discussed in this lesson is presented in Listing 13 below.

Listing 13. Listing of the program named Java3D004.

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

The purpose of this program is to illustrate the use of 
the following classes of the Java 3D API:

com.sun.j3d.utils.universe.SimpleUniverse;
com.sun.j3d.utils.geometry.Sphere;
com.sun.j3d.utils.geometry.Primitive;
javax.media.j3d.Appearance;
javax.media.j3d.Material;
javax.media.j3d.PointLight;
javax.media.j3d.BranchGroup;
javax.media.j3d.Canvas3D;
javax.media.j3d.Transform3D;
javax.media.j3d.TransformGroup;
javax.media.j3d.BoundingSphere;
javax.vecmath.Vector3f;
javax.vecmath.Point3f;
javax.vecmath.Point3d;
javax.vecmath.Color3f;


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.Sphere;
import com.sun.j3d.utils.geometry.Primitive;
import javax.media.j3d.Appearance;
import javax.media.j3d.Material;
import javax.media.j3d.PointLight;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.BoundingSphere;
import javax.vecmath.Vector3f;
import javax.vecmath.Point3f;
import javax.vecmath.Point3d;
import javax.vecmath.Color3f;
import java.awt.Frame;
import java.awt.Label;
import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;


//This is the top-level driver class for this program.
// This program could be written without the use of this
// driver class.  However, I decided to keep it intact
// for future expansions that require a user input GUI.
public class Java3D004 extends Frame{
  public static void main(String[] args){
    Java3D004 thisObj = new Java3D004();
  }//end main
  //----------------------------------------------------//

  public Java3D004(){//constructor
    setTitle("Copyright 2007, R.G.Baldwin");
    add(new Label("You can build a GUI here."));
    setBounds(236,0,235,75);
    setVisible(true);

    //Instantiate the object in which the Java 3D
    // universe will be displayed.
    TheScene theScene = new TheScene();

    //This window listener is used to terminate the
    // program when the user clicks the X button.
    addWindowListener(
      new WindowAdapter(){
        public void windowClosing(WindowEvent e){
          System.exit(0);
        }//end windowClosing
      }//end new WindowAdapter
    );//end addWindowListener

  }//end constructor
  //----------------------------------------------------//

  //This is an inner class, from which the object in which
  // the Java 3D universe will be displayed is
  // instantiated.
  class TheScene extends Frame{

    TheScene(){//constructor

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

      //Construct the objects that will be displayed in
      // the scene

      //Create and set properties for the large yellow
      // sphere.
      //Begin by describing the appearance of the surface
      // of the large sphere.  Make the color of the large
      // sphere yellow.
      Material yellowSphMaterial = new Material();
      yellowSphMaterial.setDiffuseColor(1.0f,1.0f,0.0f);
      Appearance yellowSphAppearance = new Appearance();
      yellowSphAppearance.setMaterial(yellowSphMaterial);

      //Now instantiate the large yellow sphere with 9
      // divisions.  Set the radius to 0.5. The reason for
      // setting GENERATE_NORMALS is unclear at this time.
      Sphere yellowSph = new Sphere(
                               0.5f,
                               Primitive.GENERATE_NORMALS,
                               9,
                               yellowSphAppearance);

      //Now create a small white sphere with 50 divisions.
      Material whiteSphMaterial = new Material();
      whiteSphMaterial.setDiffuseColor(1.0f,1.0f,1.0f);
      Appearance whiteSphAppearance = new Appearance();
      whiteSphAppearance.setMaterial(whiteSphMaterial);
      Sphere whiteSph = new Sphere(
                               0.10f,
                               Primitive.GENERATE_NORMALS,
                               50,
                               whiteSphAppearance);

      //Translate the location of the white sphere to make
      // it closer to the viewer than the yellow sphere at
      // the origin. Also move it down and to the left.
      Transform3D whiteTransform = new Transform3D();
      whiteTransform.setTranslation(
                          new Vector3f(-0.5f,-0.5f,0.5f));
      TransformGroup whiteTransformGroup = 
                                     new TransformGroup();
      whiteTransformGroup.setTransform(whiteTransform);
      whiteTransformGroup.addChild(whiteSph);


      //Now create a small green sphere located up to the
      // right and behind the yellow sphere.
      Material greenSphMaterial = new Material();
      greenSphMaterial.setDiffuseColor(0.0f,1.0f,0.0f);
      Appearance greenSphAppearance = new Appearance();
      greenSphAppearance.setMaterial(greenSphMaterial);
      Sphere greenSph = new Sphere(
                               0.10f,
                               Primitive.GENERATE_NORMALS,
                               50,
                               greenSphAppearance);
      Transform3D greenTransform = new Transform3D();
      greenTransform.setTranslation(
                           new Vector3f(0.5f,0.5f,-0.5f));
      TransformGroup greenTransformGroup = 
                                     new TransformGroup();
      greenTransformGroup.setTransform(greenTransform);
      greenTransformGroup.addChild(greenSph);


      //Add a white point light, in front of, to the
      // right of, and above the yellow sphere.
      Color3f pointLightColor = 
                              new Color3f(1.0f,1.0f,1.0f);
      Point3f pointLightPosition = 
                              new Point3f(1.0f,1.0f,2.0f);
      Point3f pointLightAttenuation = 
                              new Point3f(1.0f,0.0f,0.0f);

      PointLight pointLight = new PointLight(
                                   pointLightColor,
                                   pointLightPosition,
                                   pointLightAttenuation);

      //Create a BoundingSphere object and use it to
      // determine which objects to light
      BoundingSphere boundingSphere =
        new BoundingSphere(new Point3d(0.0,0.0,0.0), 1.0);
      pointLight.setInfluencingBounds(boundingSphere);

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

      //Create and populate a BranchGroup object.
      BranchGroup branchGroup = new BranchGroup();
      //Add objects to the branchGroup
      branchGroup.addChild(pointLight);
      branchGroup.addChild(yellowSph);
      //Note that adding the transform groups also adds
      // the objects contained in the groups.
      branchGroup.addChild(whiteTransformGroup);
      branchGroup.addChild(greenTransformGroup);

      //Specify the apparent location of the viewer's eye.
      simpleUniverse.getViewingPlatform().
                             setNominalViewingTransform();

      //Populate the universe by adding the branch group
      // that contains the objects.
      simpleUniverse.addBranchGraph(branchGroup);

      //Do the normal GUI stuff.
      setTitle("Copyright 2007, R.G.Baldwin");
      setBounds(0,0,235,235);
      setVisible(true);
      
      //This listener is used to terminate the program 
      // when the user clicks the X-button on the Frame.
      addWindowListener(
        new WindowAdapter(){
          public void windowClosing(WindowEvent e){
            System.exit(0);
          }//end windowClosing
        }//end new WindowAdapter
      );//end addWindowListener
      
    }//end constructor
    //--------------------------------------------------//
    
  }//end inner class TheScene

}//end class Java3D004

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

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories