| |
|
|
||||
![]() |
||||||
| |
|
|||||
|
3D
Graphics Programming in Java 3D
has the potential to allow Java programmers of all sorts to include vibrant
3D content in their applets and applications. This is fact, but not certainty,
as Sun faces heavy competition from other technologies, especially OpenGL.
Beyond the basics that every 3D API must provide, what does Java 3D have
going for it? Java 3D Transforms and Placement I received
several questions about the placement of the 3D objects in last
week's examples. One reader in particular asked why, when he modified
the transform so the cube's z coordinate was positive, he could no longer
see the cube. Let's reexamine the example code from last week's Example
3 (see Resources for links to the code archive)
to learn more about how things are situated in three dimensional space
using Java 3D. myTransform3D.setTranslation(new Vector3f(-0.5f,-0.5f,-2.3f));The arguments in the Vector3D constructor are x, y, and z coordinates. The cube is placed by this transform at x = -0.5; y = -0.5; and z = -2.3 (in floating point values, hence the "f" suffixes). It's critical to note that your viewing location can change. This is determined by the location of the associated ViewPlatform, which, in turn, is situated in the 3D world using the TransformGroup above it (actually, using a Transform3D node to transform the TransformGroup above it). Also note that in Example 3, we don't move the ViewPlatform; we construct all of the view branch using the default constructors, which use an identity Transform3D node (more on identity later) in the TransformGroup above ViewPlatform. Thus, the ViewPlatform is located at x = 0.0; y = 0.0; and z = 0.0, the origin of the 3D coordinate system. And finally, it's important to note that the coordinate system is aligned with your view into it. With the default view branch, the +x axis runs from left to right across the screen and the +y axis runs from bottom to top, which means, using the right-hand rule, that the +z axis runs out of the screen towards you. By default, your view into the world is looking in the -z direction and the origin is located in the middle of your screen.
Because you're "sitting" at the origin (the view platform is located at 0.0, 0.0, 0.0) looking in the negative-z direction, anything in the positive-z section of the 3D world is behind you and you can't see it. Don't you just love 3D! (See Resources for more information on Transform3D.) Exploring the com.sun.j3d class archives Now, let's return to the issue of the contents of Sun's private jar files. Last week I briefly mentioned that Sun's Java 3D implementation installs both standard Java 3D classes (as specified in the Java 3D API specification) and nonstandard (Sun implementation-specific) classes. These classes are made available in one of several jar archives placed within the new Java 2 platform (aka JDK 1.2 for developers) extensions directory (see last week's article for more information on this). We have discussed the standard classes and jars in sufficient detail, but we still have some ground to cover on the Sun-specific ones. As a reminder, Sun's archives include:
Now that
you know the basic layout of Sun's utility class archives, you can delve
into them more deeply if you need any of the functionality they provide.
For instance, if you're looking to capture mouse events to control interpolated
behaviors and you need to load in LightWave 3D content, you should review
com.sun.j3d.utils.behaviors.mouse, com.sun.j3d.utils.behaviors.interpolators,
and com.sun.j3d.loaders.lw3d. Behaviors and Interpolators Interactivity
results from being able to program an object to react to certain stimuli.
In Java 3D, these behaviors are scheduled when the view platform crosses
the stimulus bounds, a region of space defined by the programmer. Bounds
assign a spatial scope to objects. There are bounds for both sounds and
behaviors in Java 3D. 001 /**
002 * constructContentBranch() is where we specify the 3D graphics
003 * content to be rendered. We return the content branch group
004 * for use with our SimpleUniverse. We have added a RotationInterpolator
005 * to Example03 so that in this case, our "Gamasutra" text rotates
006 * about the origin. We have also removed the scaling and static
007 * rotation from the text, and the scaling from our ColorCube.
008 **/
009 private BranchGroup constructContentBranch() {
010 Font myFont = new Font("TimesRoman",Font.PLAIN,10);
011 Font3D myFont3D = new Font3D(myFont,new FontExtrusion());
012 Text3D myText3D = new Text3D(myFont3D, "Gamasutra");
013 Shape3D myShape3D = new Shape3D(myText3D, new Appearance());
014 Shape3D myCube = new ColorCube();
015
016 BranchGroup contentBranchGroup = new BranchGroup();
017 Transform3D myTransform3D = new Transform3D();
018 TransformGroup contentTransformGroup = new TransformGroup(myTransform3D);
019 contentTransformGroup.addChild(myShape3D);
020
021 Alpha myAlpha = new Alpha();
022 myAlpha.setIncreasingAlphaDuration(10000);
023 myAlpha.setLoopCount(-1);
024 RotationInterpolator myRotater =
025 new RotationInterpolator(myAlpha,contentTransformGroup);
026 myRotater.setAxisOfRotation(myTransform3D);
027 myRotater.setMinimumAngle(0.0f);
028 myRotater.setMaximumAngle((float)(Math.PI*2.0));
029 BoundingSphere myBounds = new BoundingSphere();
030 myRotater.setSchedulingBounds(myBounds);
031 contentTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
032 contentTransformGroup.addChild(myRotater);
033
034 contentBranchGroup.addChild(contentTransformGroup);
035
036 myTransform3D.setTranslation(new Vector3f(-0.5f,-0.5f,-2.3f));
037 TransformGroup cubeTransformGroup = new TransformGroup(myTransform3D);
038 cubeTransformGroup.addChild(myCube);
039 contentBranchGroup.addChild(cubeTransformGroup);
040
041 return(contentBranchGroup);
042 }
Reusing the World's 3D Content If you were
limited to using only content you could manually code into your Java 3D
applications, you would either limit yourself to small scene graphs with
a few nodes, or relinquish any hope of sleeping ever again. Writing Java
3D code to create complex 3D worlds from scratch is certainly nontrivial.
Realizing that such limits aren't good for the success of Java 3D (not
to mention your sanity), Sun has made it easy to import from standard
3D file formats into Java 3D using loaders. Our first loader: Wavefront OBJ Content Using ObjectFile Sun has
included support for Wavefront's OBJ and LightWave's LightWave 3D file
formats built into its implementation of Java 3D. Both formats are fairly
prevalent in the modeling and animation community, and both are well specified
and understood (again, please refer to the Loaders Archive URL for more
information on these formats). I picked the OBJ format to provide a simple
example of how to use a loader.
001 /**
002 * constructContentBranch() is where we specify the 3D graphics
003 * content to be rendered. Here we read in a cube using
004 * Sun's OBJ loader, then return this to be rendered. This
005 * cube could be replaced with more complicated content exported
006 * from 3D modeling programs supporting the OBJ format.
007 **/
008 private BranchGroup constructContentBranch() {
009 ObjectFile myOBJ = new ObjectFile();
010 Scene myOBJScene = null;
011
012 //Attempt to load in the OBJ content using ObjectFile.
013 try {
014 myOBJScene = myOBJ.load("cube.obj");
015 } catch (FileNotFoundException e) {
016 System.out.println("Could not open OBJ file...exiting");
017 System.exit(1);
018 }
019
020 //Construct and return branch group containing our OBJ scene.
021 BranchGroup contentBranchGroup = new BranchGroup();
022 contentBranchGroup.addChild(myOBJScene.getSceneGroup());
023 return(contentBranchGroup);
024 }
This method will load in the cube data, build a com.sun.j3d.utils.loaders.Scene from it, and use the scene to return a scene group that can be added to the content branch for rendering. This is the simplest possible case, however, and won't handle some of the details we would normally want to deal with (things like crease angles, which help the runtime determine how to render a scene). For a more robust OBJ loader application, we can turn to Sun's Java 3D demo app, ObjLoad. ObjLoad deals with crease angles and all the other details, sets a default background color, and provides a more mature interface to load and examine OBJ content. This demo is a good example of how Java 3D applications can take advantage of Sun's support for loaders.
VRML97 Meets Java 3D For Web-based
3D graphics, the standard to interoperate with is VRML. There has been
a lot of discussion (which will likely continue) of how and where Java
3D competes with VRML. How do the two compare?
You can test out your installation of the VRML97 browser by loading the default world, a cube similar to our previous OBJ content. Do this by changing into the VRML97 examples directory and executing the Vrml97Viewer application.
A slow 3D
graphics runtime is useless. Every ounce of speed that can be squeezed
out should be squeezed out, except of course for concessions pertaining
to usability and understandability (though some graphics programmers might
even disagree with that).
We briefly
covered capability bits last time. In a nutshell, they allow the Java
3D runtime to optimize the scene graph for faster rendering performance.
They work in concert with compilation, which I'll discuss in greater detail
in a moment. Compiling Java 3D Branch Groups When a developer
calls BranchGroup.compile(),
Java 3D checks which capability bits are set and compiles those portions
of the branch group. That is, it rearranges the applicable portion(s)
of the scene graph for optimum rendering performance. The runtime may,
in fact, do all sorts of weird things to the geometry and other nodes
of the scene graph unbeknownst to you. The net result is that things speed
up without your needing to understand all of the "magic" behind the process.
contentBranchGroup.compile(); to Example
4 to generate Example 6 (see Resources). Loose Ends Java 3D
is an interesting technology with a broad scope and an equally broad range
of tips and tricks. I have endeavored to provide you with good examples
with which to get started exploring the API, but there just isn't enough
room or time to go into all the nuances in great enough detail. I have
included more information on tips and tricks in the Resources
section to help you find your away around this exciting API.
One more
thing to note: I've received several questions on the applicability of
Java 3D to collaborative world building and interaction. I believe Java
3D to be more than capable of handling 3D rendering tasks for building
collaborative virtual worlds. There is no fundamental restriction to building
collaborative virtual worlds in Java 3D. In fact, some of Sun's customers
are building, demoing, and deploying large scale simulations and collaborative
apps using the technology today (see Sun's Java 3D product site for examples
of this).
|
|
|