3D graphics programming in Java, Part 1: Java 3D

Get a head start with this introduction to the Java 3D API

In order to build a true Java platform, Sun realized early on that it needed to fill out the API picture beyond the limited functionality available in the Java 1.0 core platform. Sun has grown the core a great deal with the 1.1 and impending 1.2 releases, but there are still some pieces missing from the Java puzzle.

Sun and its partners developed the Java Media and Communication APIs to provide the missing multimedia programming pieces. Two of the biggest pieces, 2D and 3D graphics, are targeted with the Java 2D and 3D APIs, respectively. Java 2D is a core platform API beginning with Java 1.2, while Java 3D will be released as an Extension API shortly after the 1.2 platform becomes available. We have recently finished a series of columns on Java 2D; now we turn our attention to Java 3D.

Java 3D is meant to give Java developers the ability to write applets and applications that provide three dimensional, interactive content to users. Sun has some heavy competition from other 3D graphics technologies in this arena, and Java 3D has an uphill battle ahead of it if it's to defeat the incumbent graphics standard, OpenGL.

A request for reader comments on 3D graphics APIs for Java indicated serious interest in Java 3D and Java OpenGL bindings, so I've decided to concentrate my efforts on these technologies in the coming months.

A more limited amount of interest was expressed in VRML. Consequently, I am going to deal with VRML by demonstrating its use in Java 3D with VRML97 content loaders and Sun's Java 3D VRML97 browser. Direct3D received very little interest, so I've decided not to pursue this path, except to mention where one of the other technologies may support or interoperate with it.

Pros and cons of Java 3D

This month we begin our tour of 3D graphics APIs for Java by exploring Java 3D. We'll start by discussing some of the API's major strengths and weaknesses. 3D graphics can seem at times rather obtuse and, thus, can be difficult to explain. If you have any lingering confusion about my examples or explanations, please feel free to write me with your questions or comments, and I'll do my best to address them.

Selling points for Java 3D:

  • It provides a high-level, object-oriented view of 3D graphics. Java 3D accomplishes this in part by using a scene graph-based 3D graphics model. (We'll discuss this concept in more detail later in the article.) This approach is intended to help programmers without much graphics or multimedia programming experience use 3D in their applications. In stark contrast to lower-level, procedural 3D APIs like OpenGL, which are designed to optimize for the best possible speed and give programmers the greatest possible control over the rendering process, Java 3D is meant to be straightforward enough for any experienced Java programmer to learn.

  • If you don't need low-level access to rendering operations, Java 3D may be an option. Rendering access is limited to requests via attributes and capability bits, similar in form and function to Java 2D's rendering hints. (See Resources for links to my previous series on Java 2D, which included discussion and examples of 2D's rendering hints).

  • Java 3D is optimized for speed where possible. The runtime uses rendering capability bits, in fact, to optimize the scene graph for the fastest possible renders. This approach makes Java 3D more applicable to interactive graphics environments (games, simulations, low-latency situations) than to offline, high-quality graphics applications (like render farms).

  • A large and growing number of 3D loaders are available to import content into the Java 3D runtime. Sun has made a Java 3D VRML97 file loader and browser freely available with code. Look for next month's Media Programming column to explore Java 3D loaders in more detail.

  • Java 3D requires vector math capabilities not available elsewhere in the Java platform. These math operations are currently located in the javax.vecmath package and may be moved into the core platform in the future.

  • Java 3D supports a number of exotic devices (wands, data gloves, and headsets, for example). The com.sun.j3d.utils.trackers package included with Sun's implementation provides classes for Fakespace, Logitech, and Polhemus devices. These devices are not widely used, however, so I will not discuss them in great detail. If you're interested in finding out more about device support, please refer to Sun's Java 3D sites and the Java 3D mailing list archive (both available from the main Sun Java 3D URLs included in the Resources below).

Java 3D has a lot of pros, but what about the cons? They include:

  • Java 3D is a standard extension API. Java platform licensees are given the option to implement the API if they like, but they're not required to implement it. Java 3D's positioning as a standard extension runs the risk of reducing the portability of Java 3D code across platforms -- most vendors have to struggle to keep up with changes and additions to the core platform alone.

  • Java 3D has severe availability constraints. These are the result of Java 3D's status as an extension API. The only major vendor currently providing a Java 3D implementation is Sun, with its implementations for Solaris and Win32. Compared to OpenGL, which is available for every flavor of Unix, Windows, and many other operating systems, the cross-platform portability of Java 3D code looks questionable.

  • Along with software availability problems come documentation deficits. Sun is making a valiant effort to provide developer training and support for Java 3D, but it is still falling short compared to the rest of the industry's efforts in documenting OpenGL and its use. The OpenGL Consortium's Web site is far deeper and broader than anything Sun has managed to put together for Java 3D so far. This is not a minor point: the relative complexity of 3D graphics APIs make good documentation a necessity.

  • Java 3D hides rendering-pipeline details from the developer. Because Java 3D is a high-level API, it intentionally hides details of the rendering pipeline from the developer, which makes it unsuitable for a significant number of problems where such details are important. (We'll discuss OpenGL's lower-level model and access to the rendering pipeline later in this 3D series.)

  • Java 3D components are heavyweight. That is, they have a native (non-Java) peer that actually does the rendering. This can complicate your GUI development if you use Java Swing and its all-Java, or lightweight, components. There are some special workarounds, but in general, lightweight and heavyweight components don't mix well in the same container objects and windows. More information on lightweight-heavyweight component problems is available from the Resources at the end of this article.

Installing Java 3D

Now that we understand the major features and constraints of Java 3D, let's get ready to try out some example code.

Java 3D is available in beta for Win32 and Solaris. The more mature of Sun's implementations of Java 3D is built on top of OpenGL. An alpha-quality Direct3D implementation is also available for Win32. All require Java 1.2, with the latest Java 3D beta corresponding to Java 1.2 Beta 4. Sun has promised to release the final Java 3D implementation shortly after it releases Java 1.2, which is currently scheduled for December 1998.

A slightly confusing aside: Sun released Java 3D 1.0 alpha implementations, which corresponded to the Java 3D 1.0 API, but it never released anything beyond alpha for the 1.0 API. Sun then modified the API, releasing the modified version as the Java 3D 1.1 API. This version was followed with releases of what it called 1.1 beta implementations, two so far. Sun has promised to release a final API and implementation shortly after the final release of the Java 1.2 platform. Hopefully, the API has stabilized and won't be revved, yet again, with the world still waiting on a bonafide final release of an implementation.

Because we will be covering Java OpenGL bindings in a future column, I have decided to economize and use the OpenGL version of Java 3D in these installation instructions too. If you install the OpenGL version to use with these Java 3D examples, you will have the rendering libraries you need for the Java-OpenGL examples to come later.

The software components you need to use Java 3D are:

  • Java 3D runtime, available from Sun (free Java Developer Connection login required). Be sure to choose the OpenGL version of Java 3D for your platform (I'm using Win32). As of now, the latest Win32 Java 3D for OpenGL is 1.1 Beta 2, in java3d11-beta2-win32-opengl.exe, and weighs in at approximately 1.7 MB.

  • OpenGL 1.1, bundled with Windows NT 4.0 and Windows 95 OSR 2. If you have the OSR 1 release of Windows 95, though, you can download OpenGL support. The latest Windows 95-OpenGL 1.1 implementation is available from Microsoft as opengl95.exe, and is approximately 0.5 MB.

  • Java 1.2, available from Sun. (Note that as I write this, Sun has released a new Java 1.2 -- Release Candidate 1. Examples will be updated for the latest release as soon as possible.) Java 3D is coupled into the 1.2 platform, and Sun has stated on the java3d-interest mailing list that it has no interest in decoupling the API and trying to make it available with previous platform releases.

Optionally, you may also want to download the Java 3D documentation and example code. Both are available from the same link as the Java 3D runtime.

Please note that you are no longer required to set the CLASSPATH environment variables in order for your java or appletviewer executables to find extension libraries. With Java 1.2, Sun has finally created a standard extension directory. This directory is located at /jre/lib/ext/ within your JDK installation directory. For instance, on my system, Java 1.2 Beta 4 is installed at:

C:\jdk1.2beta4\

and the standard extension directory is at:

C:\jdk1.2beta4\jre\lib\ext\

All extension libraries should place their jar archives into this extensions directory at install-time, and all standard JDK tools know to search here for needed class files.

For Sun's Java 3D, these archives include both public (documented in the Java 3D API specification) and private (Sun implementation-specific) classes. Public class archives include:

  • j3dcore.jar -- Contains class files for the public Java 3D package javax.media.j3d.

  • vecmath.jar -- Contains classes for javax.vecmath.

Private archives include:

  • j3daudio.jar -- Archives the com.sun.j3d.audio classes, which build support for spatialized audio on top of a custom copy of the Java portion of the Java Sound, Headspace-based audio engine, debuting in Java 1.2.

  • j3dutils.jar -- Encapsulates a variety of Sun utility classes in 16 total packages and subpackages underneath com.sun.j3d. I will dig deeper into these packages in next month's continuation of our Java 3D discussion.

  • j3dutilscontrib.jar -- Archives useful utilities contributed by others to Sun's efforts. There are seven packages under the com.sun.j3d hierarchy, including the com.sun.j3d.utils.trackers code mentioned above. Again, next month's column will provide more information on the packages in this jar.

Please note that in theory you may instantiate and call methods on any of the classes provided in nonstandard packages like com.sun, but caveat emptor: There is no guarantee they will be available on the platform your code executes on. In current practice, Java 3D is only available from Sun, so a lot of developers do, in fact, use classes within Sun's private archives. You should be aware of the potential portability trade-off entailed in choosing to do so.

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.

Constructing the view branch of the scene

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

Placing content into the Java 3D scene graph

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!

3D JavaWorld logo, transformed via translation, rotation, and scaling

Using Sun utility classes to make your code simpler

You may have looked at all of the set-up code in our first two examples above and wondered, Why do we have to make so many redundant method calls each time we use Java 3D? The answer is, we don't if we're willing to use Sun utility classes (or write our own).

Sun has provided a large number of utility classes to take some of the burden off of the developer. Assuming you can put up with the portability restrictions mentioned previously, these utilities can take care of simple view branch construction for you. They also provide a library of primitive shapes that you can use directly, rather than constructing objects from the smallest fragments each time.

Example 3 illustrates the use of SimpleUniverse and ColorCube utilities. Please refer to the complete source code listing for the import statements and additional information on these utilities.

001     //Now that we have our Frame and Canvas3D, we are ready
002     //to start building our scene graph.  We need to construct
003     //both a view branch and a content branch.  Using Sun's
004     //SimpleUniverse utility, we can combine the View and
005     //view branch construction into one simple step.
006     SimpleUniverse myUniverse = new SimpleUniverse(myCanvas3D);
007     BranchGroup contentBranchGroup = constructContentBranch();
008     myUniverse.addBranchGraph(contentBranchGroup);
009   }
010 
011   /**
012    * constructContentBranch() is where we specify the 3D graphics
013    * content to be rendered.  We return the content branch group
014    * for use with our SimpleUniverse.  We also demonstrate the
015    * use of com.sun.j3d.utils.geometry.ColorCube to build more
016    * complicated 3D shapes.
017    *
018   **/
019   private BranchGroup constructContentBranch() {
020     Font myFont = new Font("TimesRoman",Font.PLAIN,10);
021     Font3D myFont3D = new Font3D(myFont,new FontExtrusion());
022     Text3D myText3D = new Text3D(myFont3D, "JavaWorld");
023     Shape3D myShape3D = new Shape3D(myText3D, new Appearance());   
024     Shape3D myCube = new ColorCube();
025 
026     BranchGroup contentBranchGroup = new BranchGroup();
027     Transform3D myTransform3D = new Transform3D();
028     myTransform3D.setTranslation(new Vector3f(-1.0f,0.0f,-4.0f));
029     myTransform3D.setScale(0.1);
030     Transform3D tempTransform3D = new Transform3D();
031     tempTransform3D.rotY(Math.PI/4.0d);
032     myTransform3D.mul(tempTransform3D);
033     TransformGroup contentTransformGroup = new TransformGroup(myTransform3D);
034 
035     contentTransformGroup.addChild(myShape3D);
036     contentBranchGroup.addChild(contentTransformGroup);
037 
038     myTransform3D.setIdentity();
039     myTransform3D.setTranslation(new Vector3f(-0.5f,-0.5f,-2.3f));
040     myTransform3D.setScale(0.1);
041     TransformGroup cubeTransformGroup = new TransformGroup(myTransform3D);
042 
043     cubeTransformGroup.addChild(myCube);
044     contentBranchGroup.addChild(cubeTransformGroup);
045 
046     return(contentBranchGroup);
047   }
JavaWorld logo plus a ColorCube from Sun's utility packages

Note that the string "JavaWorld" should appear white: apparently, there is a bug in Java 3D involving the ordering of this render. I am following up with Sun personnel and will update the example source as need be to address this.

Conclusions

A vast amount of capability, and seeming complexity, lurks beneath the calm surface of the Java 3D sea. This column has shown you how to dip your toes in and go for a short swim.

Next month, we'll continue our exploration of Java 3D. I'll discuss loading VRML and other 3D content into Java 3D. I'll also discuss some of the general performance issues at work under the covers in Sun's Java 3D implementation. In the column after that, I'll compare and contrast Java OpenGL bindings with Java 3D.

I wanted to again thank everyone who stopped by to say hello at my SIGS Conference for Java Development tutorial. (I presented Programming with the Java Media APIs at JavaDevCon in late October 1998.) I greatly appreciate all the feedback I received on the tutorial and this column. As always, if you have questions or ideas for upcoming installments, please let me know.

Bill Day is a software engineer at Silicon Graphics Computer Systems and an ACM Distinguished Lecturer. In addition to writing for JavaWorld, Bill is authoring a book entitled Java Media Players for O'Reilly & Associates. When Bill is not writing or programming, he loves to mountain bike, travel with his wife, and speak French. Java, c'est magnifique!

Learn more about this topic

  • A good place to start is the Introduction to Programming with Java 3D course tutorial put together by Sun and the San Diego Supercomputer Center. http://www.sdsc.edu/~nadeau/Courses/SDSCjava3d/
  • Sun's Java 3D API page documents the API and its use. It contains javadocs for the API, the mailing list archive, Sun's Java 3D FAQ, and more. http://java.sun.com/products/java-media/3D/
  • The API is specified in Sun's Java 3D API Specification document. http://java.sun.com/products/java-media/3D/forDevelopers/j3dguide/j3dTOC.doc.html
  • The specification is also available in book format from Addison-Wesley's Java Series. Please note that the version of the API this printed specification corresponds to may be somewhat out of date The online specification is always kept up to date for the latest API release. http://www.amazon.com/exec/obidos/ASIN/0201325764/billday/
  • Sun makes its Win32 and Solaris implementations (as opposed to the API specification itself) available from a separate, product Web site. This site also contains the example code for Sun Java 3D training courses, demos from the Java 3D programming contest Sun hosted earlier in 1998, case studies with Sun's Java 3D customers, and lists of Java 3D related papers and Web pages. http://www.sun.com/desktop/java3d/index.html
  • Sun's Java 3D product site links to the course notes for its "Java 3D Roadshow." This is the crash course Sun representatives have been teaching to interested developers around the world in 1998. http://www.sun.com/desktop/java3d/collateral/j3d_clas.pdf
  • The OpenGL Consortium's Web site is the complete resource for OpenGL. http://www.opengl.org/
  • The Java 3D FAQ is maintained by Steve Pietrowicz, a project manager of the Java 3D group at NCSA. It is an excellent third-party resource for Java 3D information. http://tintoy.ncsa.uiuc.edu/~srp/java3d/faq.html
  • Read more about Java 3D's heavyweight components and Sun's thoughts on integrating them with Swing lightweight components. http://java.sun.com/products/java-media/mail-archive/3D/1520.html
  • Follow-up on Sun's plans for Java 3D vis-a-vis lightweight components and Swing. http://java.sun.com/products/java-media/mail-archive/3D/1557.html
  • "Progress on the media front at Siggraph '98" sizes up the state of Java Media in general and Java 3D in particular at this year's premier computer graphics conference. http://www.javaworld.com/javaworld/jw-10-1998/jw-10-media.html
  • Download source code and classes for this column. http://www.javaworld.com/jw-12-1998/media/jw-12-media.jar
  • Bill has archived Media Programming resources on his Web site. This archive contains the up-to-date media.jar file with code fixes for all of the examples in the column. http://reality.sgi.com/bday/Work/index.html
  • Read Bill's previous Media Programming columns. http://www.javaworld.com/topicalindex/jw-ti-media.html
Join the discussion
Be the first to comment on this article. Our Commenting Policies