Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 4 of 5
There's no magic in how the public and private Java 3D classes interface with system resources, either. Sun installs native
libraries in J3D.dll and j3daudio.dll under the /jre/bin/ directory. The Java 3D classes use native methods to call these DLLs and interface with the Win32 platform and OpenGL rendering
library. (Similar libraries exist for Solaris implementations.)
One final note on installation: The OpenGL rendering pipeline is designed to take advantage of OpenGL acceleration hardware to speed up your graphics applications. For the purposes of this column, though, you should be able to experiment with the examples without any special hardware. (In fact, I'm developing all the examples on a Pentium 150-MHz MMX laptop with no OpenGL acceleration hardware.) If you're interested in acceleration cards, you should refer to the OpenGL Web site or the Java 3D mailing list (see Resources) for more information. I plan to include a little more information in next month's Java 3D column on acceleration hardware, too.
As I noted earlier, one of the biggest strengths of the scene graph graphics model is that it allows inexperienced graphics programmers to add 3D to their applications. Traditionally, 3D programmers have had to specify where and how individual lines or other graphics primitives are to be drawn. Using a scene graph, however, the programmer simply creates a tree-like structure containing nodes that represent objects to be rendered as well as rendering instructions (such as where the viewpoint displayed to the monitor is located, physical geometry of the 3D world the programmer is creating, and relative distances between things).
In Java 3D, there are two major portions, or branches, to this tree: the view branch and the content branch. The content branch contains nodes describing the actual objects you want to render, including how to draw them, how to color them, textures to place on the primitives, how the objects are arranged in space, and how the objects should behave interactively. The view branch contains everything else, but in practice this branch is actually quite small compared to the content branch. View branches will often contain only a few nodes, while content branches may contain thousands for complicated 3D worlds.
Example 1 provides a simple example for creating a Java 3D scene graph. We see how to use the heavyweight Canvas3D component within a Frame container, how to create the view branch of the graph, and how to attach a View to it. The content branch portion is left empty, so that we render an empty universe.
001 //Comment out the following package statement to compile separately.
002 package com.javaworld.media.j3d;
003
004 import java.awt.*;
005 import java.awt.event.*;
006 import javax.media.j3d.*;
007
008 public class Example01 extends Frame {
009 /**
010 * Instantiates an Example01 object.
011 **/
012 public static void main(String args[]) {
013 new Example01();
014 }
015
016 /**
017 * The Example01 constructor sets the frame's size, adds the
018 * visual components, and then makes them visible to the user.
019 *
020 * We place a Canvas3D object into the Frame so that Java 3D
021 * has the heavyweight component it needs to render 3D
022 * graphics into. We then call methods to construct the
023 * View and Content branches of our scene graph.
024 **/
025 public Example01() {
026 //Title our frame and set its size.
027 super("Java 3D Example01");
028 setSize(400,300);
029
030 //Here is our first Java 3D-specific code. We add a
031 //Canvas3D to our Frame so that we can render our 3D
032 //graphics. Java 3D requires a heavyweight component
033 //Canvas3D into which to render.
034 Canvas3D myCanvas3D = new Canvas3D(null);
035 add("Center",myCanvas3D);
036
037 //Turn on the visibility of our frame.
038 setVisible(true);
039
040 //We want to be sure we properly dispose of resources
041 //this frame is using when the window is closed. We use
042 //an anonymous inner class adapter for this.
043 addWindowListener(new WindowAdapter()
044 {public void windowClosing(WindowEvent e)
045 {dispose(); System.exit(0);}
046 }
047 );
048
049 //Now that we have our Frame and Canvas3D, we are ready
050 //to start building our scene graph. We need to construct
051 //both a view branch and a content branch. In order to
052 //actually use our view branch, we also need to construct
053 //a View and connect it to our view branch's ViewPlatform.
054 View myView = constructView(myCanvas3D);
055 Locale myLocale = constructViewBranch(myView);
056 constructContentBranch(myLocale);
057 }
058
059 /**
060 * constructView() takes a Canvas3D reference and constructs
061 * a View to display in that Canvas3D. It uses the default
062 * PhysicalBody and PhysicalEnvironment (both required to be
063 * set or else the 3D runtime will throw exceptions). The
064 * returned View is used by constructViewBranch() to attach
065 * the scene graph's ViewPlatform to a Canvas3D for rendering.
066 *
067 * @see constructViewBranch(View)
068 **/
069 private View constructView(Canvas3D myCanvas3D) {
070 View myView = new View();
071 myView.addCanvas3D(myCanvas3D);
072 myView.setPhysicalBody(new PhysicalBody());
073 myView.setPhysicalEnvironment(new PhysicalEnvironment());
074 return(myView);
075 }
076
077
078 /**
079 * constructViewBranch() takes as input a View which we
080 * attached to our Canvas3D in constructView(). It constructs
081 * a default view branch for the scene graph, attaches
082 * the View to the ViewPlatform, and returns a reference to
083 * our Locale for use by constructContentBranch()
084 * in creating content for our scene graph.
085 *
086 * @see constructView(Canvas3D)
087 * @see constructContentBranch(Locale)
088 **/
089 private Locale constructViewBranch(View myView) {
090
091 //First, we create the necessary coordinate systems
092 //(VirtualUniverse, Locale), container nodes
093 //(BranchGroup, TransformGroup), and platform which
094 //determines our viewing position and direction (ViewPlatform).
095 VirtualUniverse myUniverse = new VirtualUniverse();
096 Locale myLocale = new Locale(myUniverse);
097 BranchGroup myBranchGroup = new BranchGroup();
098 TransformGroup myTransformGroup = new TransformGroup();
099 ViewPlatform myViewPlatform = new ViewPlatform();
100
101 //Next, we insert the platform into the transform group,
102 //the transform group into the branch group, and the branch
103 //group into the locale's branch graph portion of the
104 //scene graph.
105 myTransformGroup.addChild(myViewPlatform);
106 myBranchGroup.addChild(myTransformGroup);
107 myLocale.addBranchGraph(myBranchGroup);
108
109 //Finally, we attach our view to the view platform and we
110 //return a reference to our new universe. We are ready to
111 //render 3D content!
112 myView.attachViewPlatform(myViewPlatform);
113 return(myLocale);
114 }
115
116 /**
117 * constructContentBranch() is where we specify the 3D graphics
118 * content to be rendered into the Locale referenced
119 * in the passed parameter. Nothing is currently specified, so we
120 * render an empty universe.
121 *
122 * @see constructViewBranch(View)
123 **/
124 private void constructContentBranch(Locale myLocale) {
125 //Insert content to be rendered here.
126 }
127 }

How lonely it is in an empty universe
Now, let's provide some content to be rendered. We'll start with static content: Next month, we'll add behaviors (interactivity).
One interesting thing to note about Java 3D is that it does not provide primitives like spheres or cubes. The designers of
the API chose to instead provide robust support for things like GeometryArrays, so that developers could build up graphics primitives while allowing the Java 3D runtime to optimize as much as possible
for speed. The astute observer will note when we get to our OpenGL discussion a couple of month's hence that the primitives
provided in Java 3D closely map to those provided in OpenGL, no surprise considering the layering of Java 3D on top of OpenGL.
One result of this design decision is that you will either have to spend a lot of time creating primitives over and over again, or you will need to use a primitive library built for Java 3D.
For Example 2, we sidestep the issue by rendering a three dimensional text string. Java 3D builds on top of the new text support provided in Java 2D (see the listing of my previous columns in the Resources for more information on Java 2D and text).
Using the 3D text support, our updated constructViewBranch() method is:
001 /**
002 * constructContentBranch() is where we specify the 3D graphics
003 * content to be rendered into the VirtualUniverse referenced
004 * in the passed parameter. As an example, let's render a
005 * some three dimensional text: We render the word "JavaWorld"
006 * in Times Roman font, extruded, then translated, scaled, and
007 * rotated off of the original coordinate axes.
008 *
009 * Compare to Java 2D example com.javaworld.media.j2d.Example04:
010 * http://www.javaworld.com/javaworld/jw-07-1998/jw-07-media.html
011 *
012 * @see constructViewBranch(View)
013 **/
014 private void constructContentBranch(Locale myLocale) {
015 //We first create a regular 2D font, then from that a
016 //3D font, 3D text, and 3D shape, in succession. We use
017 //the default constructors for FontExtrusion and Appearance.
018 Font myFont = new Font("TimesRoman",Font.PLAIN,10);
019 Font3D myFont3D = new Font3D(myFont,new FontExtrusion());
020 Text3D myText3D = new Text3D(myFont3D, "JavaWorld");
021 Shape3D myShape3D = new Shape3D(myText3D, new Appearance());
022
023 //We created a new branch group and transform group to hold
024 //our content. This time when we create the transform group,
025 //however, we pass in a Transform3D to the transform group's
026 //constructor. This 3D transform has been manipulated
027 //to perform the transformations we desire, which results
028 //in those manipulations being carried out on all children
029 //of the given transform group, in this case, our content.
030 BranchGroup contentBranchGroup = new BranchGroup();
031 Transform3D myTransform3D = new Transform3D();
032 myTransform3D.setTranslation(new Vector3f(-1.0f,0.0f,-4.0f));
033 myTransform3D.setScale(0.1);
034 Transform3D tempTransform3D = new Transform3D();
035 tempTransform3D.rotY(Math.PI/4.0d);
036 myTransform3D.mul(tempTransform3D);
037 TransformGroup contentTransformGroup = new TransformGroup(myTransform3D);
038
039 //We add our child nodes and insert the branch group into
040 //the live scene graph. This results in Java 3D rendering
041 //the content.
042 contentTransformGroup.addChild(myShape3D);
043 contentBranchGroup.addChild(contentTransformGroup);
044 myLocale.addBranchGraph(contentBranchGroup);
045 }
Our universe is empty no more!