CHAPTER 15

Geometry utility classes and object loaders

15.1 Introduction

15.2 Triangulator, normal vector generator, stripifier

15.3 Object loaders

15.4 Summary

This chapter explains some of the utility classes that Java 3D supplies to help you import or generate geometry for your scenes.

15.1 Introduction

Java 3D comes with three utility classes that facilitate runtime geometry creation:

The geometry compression classes allow Java 3D to create an internal compressed representation of geometry information. If the graphics hardware supports using compressed geometry, the result may be faster rendering time and lower memory usage. Geometry compression can also be useful for applications that need to send Java 3D geometry across network connections using serialization or Java RMI. Refer to the API documentation for further details.

The Java 3D object loaders define an architecture for writing files to import geometry data into Java 3D. Sun supplies two loaders as part of the Java 3D utilities package:

In addition, the Java 3D/VRML working groups maintain a VRML loader to import VRML (WRL) files into Java 3D. The VRML loader must be downloaded separately (VRML97.JAR). The example VrmlPickingTest uses the VRML97 loader. The VRML97 loader is no longer be ing developed and is being replaced by the loaders being developed for the X3D standard, hosted at http://www.web3d.org.

15.2 Triangulator, normal vector generator, stripifier

Triangulation is a mechanism to convert arbitrary polygons to triangular surfaces for rendering. The com.sun.j3d.utils.geometry.Triangulator class can be used not only to convert an arbitrary n-sided polygon (which does not have to be planar) to triangul ar surfaces, but also to create holes in the generated composite surface. To use the Triangulator, put your vertex coordinates into a double or float array. This coordinate array should first define the outer boundary of the polygon, using counterclockwi se winding.

Then define any polygons that are to be excluded from the generated composite triangular surface. This simple example in figure 15.1 defines two contours: the outer polygon and one hole. The stripCountArray is an array of integers that delineates one con tour from the next. In figure 15.1, the stripCountArray would be

int[] stripCountArray = {4,3};

Figure 15.1

Figure 15.1 Counterclockwise winding for defining a polygon and a hole for Triangulation

Figure 15.2

Figure 15.2 Output from TriangulatorTest: The surface generated rendered both as a solid (left) and as a wireframe (right)

The first contour (A,B,C,D) contains four vertices, and the hole (F,G,H) contains three vertices.

The Triangulator class is not very well documented, so the following example should illustrate the concepts of polygon triangulation using the Triangulator class. In particular, the contourCountArray element is misleadingly documented and should be set t o the number of contours (1 + the number of holes). This is always the same as the length of the stripCountArray. Why the contourCountArray is necessary is not clear.

From TriangulatorTest.java

//Generate a surface from 10 vertices and
//create a hole in the surface by removing
//a hole defined using 5 vertices. Note that the hole
//must be entirely within the outer polygon.
private double[]  m_VertexArray = {1,1,0, //0
        0,3,0, //1
        1,5,0, //2
        2,4,0, //3
        4,5,0, //4
        3,3,0, //5
        4,2,0, //6
        4,0,0, //7
        3,0,0, //8
        2,1,0, //9
//these are vertices for the hole
        1,3,0, //10
        2,3,0, //11
        3,2,0, //12
        3,1,0, //13
        2,2,0};//14
//triangulate the polygon
GeometryInfo gi = new GeometryInfo( GeometryInfo.POLYGON_ARRAY );
gi.setCoordinates( m_VertexArray );
//the first 10 points make up the outer edge of the polygon, //the next five make up the hole int[] stripCountArray = {10,5}; int[] countourCountArray = {stripCountArray.length};
gi.setContourCounts( countourCountArray ); gi.setStripCounts( stripCountArray );
Triangulator triangulator = new Triangulator(); triangulator.triangulate( gi );
//also generate normal vectors so that the surface can be light NormalGenerator normalGenerator = new NormalGenerator(); normalGenerator.generateNormals( gi );
//create an appearance Appearance ap = new Appearance();
//render as a wireframe PolygonAttributes polyAttrbutes = new PolygonAttributes(); polyAttrbutes.setPolygonMode( PolygonAttributes.POLYGON_LINE ); polyAttrbutes.setCullFace( PolygonAttributes.CULL_NONE ) ; ap.setPolygonAttributes( polyAttrbutes );
//add both a wireframe and a solid version //of the triangulated surface Shape3D shape1 = new Shape3D( gi.getGeometryArray(), ap ); Shape3D shape2 = new Shape3D( gi.getGeometryArray() );

After the geometry has been triangulated and normal vectors have been calculated, the geometry can be very easily stripified:

//invoke the Stripifier on the GeometryInfo
Stripifier st = new Stripifier()
st.stripify(gi);
//extract the stripified GeometryArray Shape3D shape2 = new Shape3D( gi.getGeometryArray() );

15.3 Object loaders

Sun has defined the com.sun.j3d.loaders.Loader interface that provides a standard set of methods for accessing the information read in from a 3D data file format. Because there is such a wide variety of 3D data file formats available, the Loader interfac e is fairly high level and does not return graphical information directly but encapsulates it in an object implementing the Scene interface.

15.3.1 LoaderBase

java.lang.Object
  |
  +--com.sun.j3d.loaders.LoaderBase

LoaderBase is a convenience class to manage the setting and retrieval of typical Loader information, such as base URL and load flags. Developers implementing their own Loader can populate, return, and interrogate a LoaderBase instance to provide a consis tent API for end-user developers.

15.3.2 SceneBase interface

java.lang.Object
  |
  +--com.sun.j3d.loaders.SceneBase

SceneBase is a convenience class to manage the setting and retrieval of typical Scene information, such as:

Developers implementing their own Loader can populate, return, and interrogate a SceneBase instance to provide a consistent API for end-user developers.

15.3.3 Using the ObjectFile loader

The following example loads a simple Wavefront format .obj file (the hand1.obj file from the Sun Morphing demo). Note that it is also necessary to create lights for the scene and assign an Appearance and Material to the loaded Wavefront object. Figure 15 .3 shows rendered output.

Figure 15.3

Figure 15.3 A Wavefront OBJ file loaded using the Sun ObjectFile loader

From LoaderTest.java

protected BranchGroup createSceneBranchGroup()
{
 BranchGroup objRoot = super.createSceneBranchGroup();
//create a TransformGroup to flip the hand onto its end //and enlarge it. TransformGroup objTrans1 = new TransformGroup(); Transform3D tr = new Transform3D(); objTrans1.getTransform( tr ); tr.rotX(90.0 * Math.PI / 180.0); tr.setScale( 10.0 ); objTrans1.setTransform( tr );
//create a TransformGroup to rotate the hand TransformGroup objTrans2 = new TransformGroup(); objTrans2.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); objTrans2.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
BoundingSphere bounds = new BoundingSphere( new Point3d(0.0,0.0,0.0), 100.0);
//create a RotationInterpolator behavior to rotate the hand 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, objTrans2, yAxis, 0.0f, (float) Math.PI*2.0f); rotator.setSchedulingBounds(bounds); objTrans2.addChild(rotator);
//Set up the global lights Color3f lColor1 = new Color3f(0.7f, 0.7f, 0.7f); Vector3f lDir1 = new Vector3f(-1.0f, -1.0f, -1.0f); Color3f alColor = new Color3f(0.2f, 0.2f, 0.2f);
AmbientLight aLgt = new AmbientLight(alColor); aLgt.setInfluencingBounds(bounds); DirectionalLight lgt1 = new DirectionalLight(lColor1, lDir1); lgt1.setInfluencingBounds(bounds);
objRoot.addChild(aLgt); objRoot.addChild(lgt1);
//load the object file Scene scene = null; Shape3D shape = null;
//read in the geometry information from the data file ObjectFile objFileloader = new ObjectFile( ObjectFile.RESIZE );
try { scene = objFileloader.load( "hand1.obj"); } catch (Exception e) { scene = null; System.err.println(e); }

if( scene == null ) System.exit(1);
//retrieve the Shape3D object from the scene BranchGroup branchGroup = scene.getSceneGroup(); shape = (Shape3D) branchGroup.getChild(0);
//create an Appearance and Material Appearance app = new Appearance(); Color3f objColor = new Color3f(1.0f, 0.7f, 0.8f); Color3f black = new Color3f(0.0f, 0.0f, 0.0f); app.setMaterial(new Material(objColor, black, objColor, black, 80.0f));
//assign the appearance to the Shape shape.setAppearance( app );
//connect the scenegraph objTrans2.addChild( scene.getSceneGroup() ); objTrans1.addChild( objTrans2 ); objRoot.addChild( objTrans1 );
return objRoot; }

15.3.4 Third-party object loaders

There are a wide variety of object loaders available for use with Java 3D. The list of available loaders is maintained by Bill Day at http://www.j3d.org. Data file loaders available for most of the common 3D data file formats are listed in table 15.1.

Table 15.1 Data file loaders
Loader Author File Format(s) Last Updated
Milkshape3D Loader Gregory Pierce Milkshape3D 30 Aug 2001
Milkshape3D Loader Kevin Duling Milkshape3D 28 Aug 2001
AC3D Loader Ryan Wilhm/j3d.org AC3D 28 Aug 2001
NCSA Portfolio NCSA 3DS (3D-Studio)
PDB (Protein Data Bank)
DEM (Digital Elevation Map)
IOB (Imagine)
COB (Caligari trueSpace)
OBJ (Wavefront)
DXF (Drawing Interchange File)
AutoCAD
VRML 97
PLAY
15 Sept 2000
Xj3D Loader Extensible 3D (X3D) Task Group
(former VRML97-Java Working Group)
VRML97
X3D
15 Sept 2000
FullSail OpenFLT Loader Shawn Kendall OpenFLT 1 Aug 1999
Lw3dLoader Sun LWS (Lightwave Scene Format) uses LWO (Lightwave Object Format) 13 Jun 1998
ObjLoad Sun OBJ (Wavefront) 12 Jun 1998
NFF & OBJ Loader Scott Metzger NFF (WorldToolKit)
OBJ (Wavefront)
15 Jun 1998
Loader3DS Starfire Research 3DS(3D-Studio) March 2001
Import3DS Aaron Mulder 3DS (3D-Studio) 13 Jun 1998
Load3DS Wesley Layne 3DS (3D-Studio) 25 Feb 2001
Load3DS Rycharde Hawkes 3DS (3D-Studio) 16 Jun 1998
VTK Loader Arish Ali VTK (Visual Toolkit) 15 Sept 2000

Different loaders have different limitations and bugs. You should experiment with loaders and file formats until you find one that works for the files you need to display.

15.4 Summary

Java 3D includes relatively basic support for processing geometry using the utility classes in the com.sun.j3d.utils.geometry package. The utilities are easy to use, and are useful for simple triangulation. For more powerful geometry manipulation operati ons (such as mesh generation or decimation you will have to convert one of the many utility libraries, usually written in C).

The interfaces and classes defined in the com.sun.j3d.loaders package however have proved to be very useful. They have defined a standard upon which many of the community Java 3D developers can build, and a large variety of loaders have been released—mos t are free.

[previous]  |  [main]  |  [next]