Creating the Scene


Particle Systems in Java 3D

There are several ways of implementing a particle system in Java 3D, but concerns about efficiency mean that many of them are impractical for large systems. In this chapter, particles are represented as elements of a Java 3D GeometryArray. The example in this chapter displays three different types of systems, but they all use subclasses of GeometryArray: a PointArray is employed to store particles as points, a LineArray for particles which are lines, and a QuadArray is used for quads.

The standard approach to using GeometryArray is to make changes to it by copying in new coordinates, colors, etc. This approach introduces two copies of the geometry: one stored internally by Java 3D (the GeometryArray instance) and another in the user's program (usually arrays of coordinates, colors, and so on). When users change their data, they must make sure to update the version maintained by Java 3D. The sample application avoids this approach, since the rapidly changing nature of a particle system and its size would necessitate large amounts of copying, which is just too slow.

The alternative is to link the GeometryArray to the data stored in the user's program. This means users only need to update their version of the data, and Java 3D's GeometryArray will be automatically changed since it's a reference to the user's data. There's no need for copying, and there's a reduction in memory requirements since the data is only stored in one place, in the users' code. This is the approach used in this chapter.

The GeometryArray is created with a BY_REFERENCE flag:

     // a BY_REFERENCE PointArray with numPoints points     PointArray pointParts = new PointArray(numPoints,                   PointArray.COORDINATES | PointArray.COLOR_3 |                   PointArray.BY_REFERENCE );         // allow things to be read and written by reference     pointParts.setCapability(GeometryArray.ALLOW_REF_DATA_READ);     pointParts.setCapability(GeometryArray.ALLOW_REF_DATA_WRITE); 

The flag signals that the data managed by the PointArray isn't copied; instead, the PointArray refers to data structures stored in the user's execution space. pointParts will reference two data structures: one maintaining the coordinates of the PointArray and the other the colors of the points at those coordinates.

The next step is to create the local data structures utilized by pointParts. Java 3D 1.3 only supports references to float arrays:

     private float[] cs, cols;         cs = new float[numPoints*3];   // to store each (x,y,z) coord     cols = new float[numPoints*3];     // fill in the arrays with coordinates and colors         // store coordinates and colors array refs in PointArray     pointParts.setCoordRefFloat(cs);    // use BY_REFERENCE     pointParts.setColorRefFloat(cols); 

The restriction to float arrays means the coordinates must be stored as individual x-, y-, and z-values, which requires a numPoints*3 size array. Similarly, the red-green-blue components of each color must be stored separately.

Once the arrays have been filled, the references are set up with calls to setCoordRefFloat( ) and setColorRefFloat( ). After these methods have been called, the program need only change the cs and cols arrays to change the PointArray. There's no need to copy the changes into the PointArray.

pointParts becomes the geometry of a scene graph node, such as a Shape3D, with:

     setGeometry(pointParts); 

Java 3D will render the shape using the data in PointArray and update the shape when the referenced float arrays are modified.

Referring to Float Arrays

The Java 3D distribution comes with several demos using BY_REFERENCE geometry; the most relevant to understanding referenced geometries is the GeometryByReferenceTest application, available in <JAVA HOME>/demo/java3d/GeometryByReference/. The code sets up references to Point3f and Color3f arrays with the following methods:

     setCoordRef3f(  );     setColorRef3f(  ); 

However, these methodsand similar ones for textures and normalsare deprecated in Java 1.3, and the GeometryByReference demo has not been updated. The reason for the deprecation is to reduce the work required by Java 3D to maintain the references.

Synchronization Problems

An important issue is when the user's program should update the float arrays referenced by the geometry. The simplebut wronganswer is "whenever it wants" as this may lead to synchronization problems. Java 3D will periodically access the arrays to use their information for rendering the geometry, and problems may occur if this examination is intertwined with the arrays being changed by the user's code. The nasty aspect of synchronization bugs is their time-dependency, which makes them hard to detect during testing.

Synchronization worries are avoided by using Java 3D's GeometryUpdater interface to update the geometry:

     public class PointsUpdater implements GeometryUpdater     {       public void updateData(Geometry geo)       {  PointArray pa = (PointArray) geo;          float[] cs = pa.getCoordRefFloat(  );    // use BY_REFERENCE          float[] cols = pa.getColorRefFloat(  );           // update the cs and cols float arrays       }           // other support methods     } 

Java 3D passes a GeometryArray reference to the updateDate( ) method when it's safe for the user's program to carry out changes. The reference must be cast to the right type, and then the getCoordRefFloat( ) and getColorRefFloat( ) methods are used to return references to the required float arrays. The arrays can be safely modified, and the changes will be utilized by Java 3D when it next renders the geometry.

A GeometryUpdater object is set up like so:

     PointsUpdater updater = new PointsUpdater(  );     // I can now request an update of the pointParts PointArray geometry     pointParts.updateData(updater); 

Rather confusingly, the updating of the pointParts geometry involves two Java 3D methods called updateData( ), which are doing slightly different things.

The call to updateData( ) in pointParts is processed by GeometryArray.updateData( ), which requests that Java 3D carry out an update. The method argument is the PointsUpdater object, which will be called by Java 3D when it's safe to perform an update. At that point, Java 3D calls the GeometryUpdater.updateData( ) method implemented in the PointsUpdater class.

The Inner Class Coding Style

A particle system consists of three classes:

  • The particle system class containing the BY_REFERENCE geometry (e.g., a PointArray, LineArray, or QuadArray), the float arrays holding the referenced coordinates, colors, and so on. The class will hold the particle attribute initialization code.

  • A GeometryUpdater implementation, which carries out an update of the particle system by changing various attributes in the particles. This means accessing and changing the particle system's float arrays.

  • A Behavior class which is triggered periodically and then calls the geometry's updateData( ) method, thereby requesting an update.

This functionality requires a substantial amount of shared data between the classes. Consequently, the particle systems detailed in this chapter will use inner classes to implement the Behavior and GeometryUpdater classes. An added benefit of this strategy is the inner classes will be hidden from the user of the particle system.

The coding style is illustrated in Figure 21-4, which shows a simplified class diagram for the PointParticles class, which manages the particle system made of points.

The details of each of these classes will be explained in subsequent sections.


The other two particle systems in the Particles3D application have the same basic structure.



Killer Game Programming in Java
Killer Game Programming in Java
ISBN: 0596007302
EAN: 2147483647
Year: 2006
Pages: 340

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net