Contents Previous Next

Java 3D API Specification


C H A P T E R1

Introduction to Java 3D




1.1 What is Java 3D?

The Java 3D API is an application programming interface used for writing three-dimensional graphics applications and 3D applets. It gives developers high level constructs for creating and manipulating 3D geometry and for constructing the structures used in rendering that geometry. Application developers can describe very large virtual worlds using these constructs, which provides Java 3D with enough information to render these worlds efficiently.

Java 3D delivers Java's "write once, run anywhere" benefit to developers of 3D graphics applications. Java 3D is part of the JavaMedia suite of APIs, making it available on a wide range of platforms. It also integrates well with the Internet because applications and applets written using the Java 3D API also have access to the entire set of Java classes.

The Java 3D API draws its ideas from existing graphics APIs and from new technologies. Java 3D's low-level graphics constructs synthesize the best ideas found in low-level APIs such as Direct3D, OpenGL, QuickDraw3D, and XGL. Similarly, it's higher-level constructs synthesize the best ideas found in several scene-graph-based systems. Java 3D introduces some concepts not commonly considered part of the graphics environment, such as 3D spatial sound. Java 3D's sound capabilities help to provide a more immersive experience for the user.

1.2 Goals

Java 3D was designed with several goals in mind. Chief among them was high performance. Several design decision were made so that Java 3D implementations could deliver the highest level of performance to application users. In particular, when trade-offs were made, the alternative that benefited runtime execution was chosen.

Other important Java 3D goals:

1.3 Programming Paradigm

Java 3D is an object-oriented API. Applications construct individual graphics elements as separate objects and connect them together into a tree-like structure called a scene graph. The application manipulates these objects using their predefined accessor, mutator, and node-linking methods.

1.3.1 The Scene Graph Programming Model

Java 3D's scene graph-based programming model provides a simple and flexible mechanism for representing and rendering scenes. The scene graph contains a complete description of the entire scene, or virtual universe. This includes the geometric data, the attribute information, and the viewing information needed to render the scene from a particular point of view. Chapter 2, "Scene Graph Overview," provides more information on the Java 3D scene graph programming model.

The Java 3D API improves on previous graphics APIs by eliminating many of the bookkeeping and programming chores that those APIs impose. Java 3D allows the programmer to think about geometric objects rather than about triangles-about the scene and its composition rather than about how to write the rendering code for efficiently displaying the scene.

1.3.2 Rendering Modes

Java 3D includes three different rendering modes: immediate mode, retained mode, and compiled-retained mode (see Chapter 11, "The Java 3D Execution and Rendering Model"). Each successive rendering mode allows Java 3D more freedom in optimizing an application's execution. Most Java 3D applications will want to take advantage of the convenience and performance benefits that retained and compiled-retained modes provide.

1.3.2.1 Immediate Mode

Immediate mode leaves little room for global optimization at the scene graph level. Even so, Java 3D has raised the level of abstraction and does accelerate immediate mode rendering on a per-object basis. An application must provide a Java 3D draw method with a complete set of points, lines, or triangles that are then rendered by the high-speed Java 3D renderer. Of course, the application can build these lists of points, lines, or triangles in any manner it chooses.

1.3.2.2 Retained Mode

Retained mode requires an application to construct a scene graph and specify which elements of that scene graph may change during rendering. The scene graph describes the objects in the virtual universe, the arrangement of those objects, and how the application animates those objects.

1.3.2.3 Compiled-Retained Mode

Compiled-retained mode, like retained mode, requires the application to construct a scene graph and specify which elements of the scene graph may change during rendering. Additionally, the application can compile some, or all, of the subgraphs that make up a complete scene graph. Java 3D compiles these graphs into an internal format. The compiled representation of the scene graph may bear little resemblance to the original tree structure provided by the application. However, it is functionally equivalent.

1.3.3 Extensibility

Most Java 3D classes expose only accessor and mutator methods. Those methods only operate on that object's internal state, making it meaningless for an application to override them. Therefore, Java 3D declares most methods as final.

Applications can extend Java 3D's classes and add their own methods. However, they may not override Java 3D's scene graph traversal semantics because the nodes do not contain explicit traversal and draw methods. Java 3D's renderer retains those semantics internally.

Java 3D does provide hooks for mixing Java 3D-controlled scene graph rendering and user-controlled rendering using Java 3D's immediate mode constructs (see Section 12.1.2, "Mixed Mode Rendering"). Alternatively, the application can stop Java 3D's renderer and do all its drawing in immediate mode (see Section 12.1.1, "Pure Immediate Mode Rendering").

Behaviors require applications to extend the Behavior object and to override its methods with user-written Java code. These extended objects should contain references to those scene graph objects that it will manipulate at runtime. Chapter 10, "Behaviors, Interpolators, and Picking," describes Java 3D's behavior model.

1.4 High Performance

Java 3D's programming model allows the Java 3D API to do the mundane tasks, such as scene graph traversal, managing attribute state changes, etc., thereby simplifying the application's job. Java 3D does this without sacrificing performance. At first glance, it might appear that this approach would create more work for the API. However, it actually has the opposite effect. Java 3D's higher level of abstraction not only changes the amount, but more importantly, the kind of work the API must perform. This means that Java 3D need not impose the same type of constraints as do APIs with a lower level of abstraction. This allows Java 3D to introduce optimizations not possible with these lower-level APIs.

Additionally, leaving the details of rendering to Java 3D allows it to tune the rendering to the underlying hardware. For example, relaxing the strict rendering order imposed by other APIs allows parallel traversal as well as parallel rendering. Knowing which portions of the scene graph cannot be modified at runtime allows Java 3D to flatten the tree, pre-transform geometry, or represent the geometry in a native hardware format without the need to keep the original data.

1.4.1 Layered Implementation

Besides optimizations at the scene graph level, one of the more important factors that determines the performance of Java 3D is the time it takes to render the visible geometry. Java 3D implementations are layered to take advantage of the native, low-level API that is available on a given system. In particular, Java 3D implementations that use Direct3D, OpenGL, and QuickDraw3D will be available. This means that Java 3D rendering will be accelerated across the same wide range of systems that are supported by these lower-level APIs.

1.4.2 Target Hardware Platforms

Java 3D is aimed at a wide range of 3D-capable hardware and software platforms, from low cost PC game cards and software renderers at the low end, through mid-range workstations, all the way up to very high-performance, specialized, 3D image generators.

It is expected that Java 3D implementations will provide useful rendering rates on most modern PCs, especially those with 3D graphics accelerator cards. On mid-range workstations, Java 3D is expected to provide applications with nearly full-speed hardware performance.

Finally, Java 3D was designed to scale as the underlying hardware platforms increase in speed over time. Tomorrow's 3D PC game accelerators will support more complex virtual worlds than high-priced workstations of a few years ago. Java 3D is prepared to meet this increase in hardware performance.

1.5 Support for Building Applications and Applets

Java 3D neither anticipates nor directly supports every possible 3D need. Instead it provides support to add those features through Java code.

Objects defined using a Computer Aided Design (CAD) system or an animation system may be included in a Java 3D-based application. Most such modeling packages have a (sometimes proprietary) external format. Designers can export to a file geometry designed using an external modeler. Java 3D can use that geometric information, but only if an application provides a means for reading and translating the modeler's file format into Java 3D primitives.

Similarly, VRML loaders will parse and translate VRML files and generate the appropriate Java 3D objects and Java code necessary to support the file's contents.

1.5.1 Browsers

Today's Internet browsers support 3D content by passing such data to plug-in 3D viewers that render into their own window. It is anticipated that, over time, the display of 3D content will become integrated into the main browser display. In fact, some of today's 3D browsers display 2D content as 2D objects within a 3D world.

1.5.2 Games

Developers of 3D game software have typically attempted to wring out every last ounce of performance from the hardware. Historically they have been quite willing to use hardware-specific, non-portable optimizations to get the best performance possible. As such, in the past, game developers have tended to program below the level of easy-to-use software such as Java 3D. However, the trend in 3D games today is to leverage general purpose 3D hardware accelerators and to use fewer "tricks" in rendering.

So, while Java 3D was not explicitly designed to match the game developer's every expectation, Java 3D's sophisticated implementation techniques should provide more than enough performance to support many game applications. One might argue that applications written using a general API like Java 3D may have a slight performance penalty over those employing special non-portable techniques. However, other factors such as portability, time to market, and development cost must be weighed against absolute peak performance.

1.6 Overview of Java 3D Object Hierarchy

Java 3D defines several basic classes that are used to construct and manipulate a scene graph and to control viewing and rendering. Figure 1-1 shows the overall object hierarchy used by Java 3D. Subsequent chapters provide more detail for specific portions of the hierarchy.

1.7 Structuring the Java 3D Program

1.7.1 Java 3D Application Scene Graph

The following simple example shows how a developer might structure a Java 3D application. This simple application draws an object in the center of a window and rotates the object about its center point. Figure 1-2 shows the scene graph for such an application.

The scene graph consists of superstructure components-a VirtualUniverse object and a Locale object-and scene graph branches, or subgraphs. Each subgraph is rooted by a BranchGroup node that is attached to the superstructure. For more information, see Chapter 2, "Scene Graph Overview."

A VirtualUniverse object defines a named universe. Java 3D permits the creation of more than one universe, though the vast majority of applications will use just one. The VirtualUniverse object provides a grounding for scene graphs. All Java 3D scene graphs must connect to a Virtual Universe object to be displayed. For more information, see Chapter 3, "Scene Graph Superstructure."

Below the VirtualUniverse object is a Locale object. The Locale object defines the origin, in high-resolution coordinates, of its attached subgraphs. A Virtual Universe may contain as many Locales as needed. In this example, a single Locale object is defined with its origin at (0.0, 0.0, 0.0).

The scene graph itself starts with the BranchGroup nodes (see Section 4.2, "BranchGroup Node"). A BranchGroup serves as the root of a subgraph, or branch, of the scene graph-only BranchGroup objects can attach to Locales.

In this example there are two subgraphs and, thus, two BranchGroup nodes. Attached to the left BranchGroup are two subtrees. One subtree consists of a user-extended Behavior leaf node. The Behavior node contains Java code to manipulate the transform matrix associated with the object's geometry.

The other subtree in this BranchGroup consists of a TransformGroup node that specifies the position (relative to the Locale), the orientation and the scale of the geometric object in the virtual universe. A single child, a Shape3D leaf node, refers to two component objects: a Geometry object and an Appearance object. The Geometry object describes the geometric shape of a 3D object (a cube in our simple example). The Appearance object describes the appearance of the geometry (color, texture, material reflection characteristics, etc.).

The right BranchGroup has a single subtree that consists of a TransformGroup node and a ViewPlatform leaf node. The TransformGroup specifies the position (relative to the Locale), the orientation and the scale of the ViewPlatform. This transformed ViewPlatform object defines the end user's view within the virtual universe.

Finally, the ViewPlatform is referenced by a View object that specifies all of the parameters needed to render the scene from the point of view of the ViewPlatform. Also referenced by the View object are other objects that contain information such as the drawing canvas that Java 3D renders into, the screen that contains the canvas, and information about the physical environment.

1.7.2 Recipe for Java 3D Program

The following steps are taken by the example program to create the scene graph elements and link them together. Java 3D will then render the scene graph and display it in a window on the screen:

The Java 3D renderer then starts running in an infinite loop. The renderer conceptually performs the following operations:

while(true) {
    Process input
    If (request to exit) break
    Perform Behaviors
    Traverse the scene graph and render visible objects
}
Cleanup and exit

1.7.3 HelloUniverse: A Sample Java 3D Program

Here is a code fragment from a simple program, HelloUniverse.java, that creates a cube and behavior object that rotates the cube at a constant rate of /2 radians per second.

public class HelloUniverse extends Applet {
    public BranchGroup createSceneGraph() {
        // Create the root of the subgraph
        BranchGroup objRoot = new BranchGroup();

        // Create the transform group node and initialize it to the
        // identity.  Enable the TRANSFORM_WRITE capability so that
        // our behavior code can modify it at runtime.  Add it to the
        // root of the subgraph.
        TransformGroup objTrans = new TransformGroup();
        objTrans.setCapability(
                            TransformGroup.ALLOW_TRANSFORM_WRITE);
        objRoot.addChild(objTrans);
        // Create a simple shape leaf node, add it to the scene graph.
        objTrans.addChild(new ColorCube().getShape());

        // Create a new Behavior object that will perform the desired
        // operation on the specified transform object and add it into
        // the scene graph.
        Transform3D yAxis = new Transform3D();
        Alpha rotationAlpha = new Alpha(
                -1, Alpha.INCREASING_ENABLE,
                0, 0,            4000, 0, 0,                        0, 0, 0);
        RotationInterpolator rotator = new RotationInterpolator(
                rotationAlpha, objTrans, yAxis,
                0.0f, (float) Math.PI*2.0f);
        BoundingSphere bounds =
            new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
        rotator.setSchedulingBounds(bounds);
        objTrans.addChild(rotator);

        return objRoot;
    }

    public HelloUniverse() {
        setLayout(new BorderLayout());
        Canvas3D c = new Canvas3D();
        add("Center", c);
        // Create a simple scene and attach it to the virtual universe
        BranchGroup scene = createSceneGraph();
        UniverseBuilder u = new UniverseBuilder(c);
        u.addGraph(scene);
    }
}
public class UniverseBuilder extends Object {
    // User-specified canvas
    Canvas3D canvas;

    // Scene graph elements that the user may want access to
    VirtualUniverse                        universe;
    Locale                        locale;
    TransformGroup                        vpTrans;
    View                        view;

    public UniverseBuilder(Canvas3D c) {
        this.canvas = c;

        // Establish a virtual universe, with a single hi-res Locale
        universe = new VirtualUniverse();
        locale = new Locale(universe);

        // Create a PhysicalBody and Physical Environment object
        PhysicalBody body = new PhysicalBody();
        PhysicalEnvironment environment =
                                            new PhysicalEnvironment();

        // Create a View and attach the Canvas3D and the physical
        // body and environment to the view.
        view = new View();
        view.addCanvas3D(c);
        view.setPhysicalBody(body);
        view.setPhysicalEnvironment(environment);

        // Create a branch group node for the view platform
        BranchGroup vpRoot = new BranchGroup();

        // Create a ViewPlatform object, and its associated
        // TransformGroup object, and attach it to the root of the
        // subgraph.  Attach the view to the view platform.
        Transform3D t = new Transform3D();
        t.set(new Vector3f(0.0f, 0.0f, 5.0f));
        ViewPlatform vp = new ViewPlatform();
        TransformGroup vpTrans = new TransformGroup(t);

        vpTrans.addChild(vp);
        vpRoot.addChild(vpTrans);

        view.attachViewPlatform(vp);
        view.setFieldOfView(40.0 * Math.PI / 180.0);
        view.setFrontClipDistance(1.0);
        view.setBackClipDistance(10.0);

        // Attach the branch graph to the universe, via the Locale.
        // The scene graph is now live!
        locale.addBranchGraph(vpRoot);
    }

    public void addBranchGraph(BranchGroup bg) {
        locale.addBranchGraph(bg);
    }
}
public class ColorCube extends Object {
    private static final float[] verts = {
    // front face
         1.0f, -1.0f,  1.0f,                             1.0f,  1.0f,  1.0f,
        -1.0f,  1.0f,  1.0f,                            -1.0f, -1.0f,  1.0f,
    // back face
        -1.0f, -1.0f, -1.0f,                            -1.0f,  1.0f, -1.0f,
         1.0f,  1.0f, -1.0f,                             1.0f, -1.0f, -1.0f,
    // right face
         1.0f, -1.0f, -1.0f,                             1.0f,  1.0f, -1.0f,
         1.0f,  1.0f,  1.0f,                             1.0f, -1.0f,  1.0f,
    // left face
        -1.0f, -1.0f,  1.0f,                            -1.0f,  1.0f,  1.0f,
        -1.0f,  1.0f, -1.0f,                            -1.0f, -1.0f, -1.0f,
    // top face
         1.0f,  1.0f,  1.0f,                             1.0f,  1.0f, -1.0f,
        -1.0f,  1.0f, -1.0f,                            -1.0f,  1.0f,  1.0f,
    // bottom face
        -1.0f, -1.0f,  1.0f,                            -1.0f, -1.0f, -1.0f,
         1.0f, -1.0f, -1.0f,                             1.0f, -1.0f,  1.0f,
    };
    private static final float[] colors = {
    // front face (red)
        1.0f, 0.0f, 0.0f,                            1.0f, 0.0f, 0.0f,
        1.0f, 0.0f, 0.0f,                            1.0f, 0.0f, 0.0f,
    // back face (green)
        0.0f, 1.0f, 0.0f,                            0.0f, 1.0f, 0.0f,
        0.0f, 1.0f, 0.0f,                            0.0f, 1.0f, 0.0f,
    // right face (blue)
        0.0f, 0.0f, 1.0f,                            0.0f, 0.0f, 1.0f,
        0.0f, 0.0f, 1.0f,                            0.0f, 0.0f, 1.0f,
    // left face (yellow)
        1.0f, 1.0f, 0.0f,                            1.0f, 1.0f, 0.0f,
        1.0f, 1.0f, 0.0f,                            1.0f, 1.0f, 0.0f,
    // top face (magenta)
        1.0f, 0.0f, 1.0f,                            1.0f, 0.0f, 1.0f,
        1.0f, 0.0f, 1.0f,                            1.0f, 0.0f, 1.0f,
    // bottom face (cyan)
        0.0f, 1.0f, 1.0f,                            0.0f, 1.0f, 1.0f,
        0.0f, 1.0f, 1.0f,                            0.0f, 1.0f, 1.0f,
    };

    private Shape3D shape;

    public ColorCube() {
        QuadArray cube = new QuadArray(24,
                        QuadArray.COORDINATES | QuadArray.COLOR_3);

        cube.setCoordinates(0, verts);
        cube.setColors(0, colors);

        shape = new Shape3D(cube, new Appearance());
    }

    public Shape3D getShape() {
        return shape;
    }
}



Contents Previous Next

Java 3D API Specification


Copyright © 1997, Sun Microsystems, Inc. All rights reserved.