A Fountain of Quads


A Fountain of Points

PointsParticles creates a fountain of points, whose points are colored yellow initially but gradually turn red. The particles are emitted from the origin and travel in parabolas of various velocities in any direction across the XZ plane and upwards along the y-axis. The only force applied to the particles is gravity which will affect their acceleration and velocity over time. When a particle drops below the XZ plane, it's reused by having its attributes reset to their initial settings.

A particle has four attributes:

  • Its (x, y, z) location

  • Its velocity (expressed in x-, y-, and z-directional components)

  • Its acceleration (also expressed as three components)

  • Its color (as three floats for its Red/Green/Blue parts)

The class diagram for PointParticles is shown in Figure 21-4. The attributes are represented by the float arrays cs, vels, accs, and cols. If the user starts the PointParticles system with numPoints particles, these arrays will be sized at numPoints*3 to accommodate all the necessary data.

The PointParticles( ) constructor initializes the PointArray as outlined:

     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 constructor creates the GeometryUpdater and Behavior objects:

     PointsUpdater updater = new PointsUpdater(  );     partBeh = new PartclesControl(delay, updater); 

partBeh is a global so it can be returned by getParticleBeh( ):

     public Behavior getParticleBeh(  )     { return partBeh;  } 

The constructor calls createGeometry( ) to initialize the Shape3D's geometry and createAppearance( ) for its appearance.

The Particle System's Geometry and Appearance

createGeometry( ) declares the float arrays, initializes them, and sets up references to the coordinate and color float arrays for the PointArray:

     private void createGeometry(  )     { cs = new float[numPoints*3];   // to store each (x,y,z)       vels = new float[numPoints*3];       accs = new float[numPoints*3];       cols = new float[numPoints*3];           // step in 3's == one (x,y,z) coord       for(int i=0; i < numPoints*3; i=i+3)         initParticle(i);           // store the coordinates and colors in the PointArray       pointParts.setCoordRefFloat(cs);    // use BY_REFERENCE       pointParts.setColorRefFloat(cols);           setGeometry(pointParts);     } 

pointParts is only set to refer to the cs and cols arrays since these contain the position and color data required for each point. GeometryArrays may be assigned normals and texture coordinates, as you'll see in the QuadParticles class.

initParticles( ) is called in steps of three, as each iteration is initializing one point, which is equivalent to three values in the float arrays:

     private void initParticle(int i)     { cs[i] = 0.0f; cs[i+1] = 0.0f; cs[i+2] = 0.0f;             // (x,y,z) at origin       // random velocity in XZ plane with combined vector XZ_VELOCITY       double xvel = Math.random(  )*XZ_VELOCITY;       double zvel = Math.sqrt((XZ_VELOCITY*XZ_VELOCITY) - (xvel*xvel));       vels[i] = (float)((Math.random(  )<0.5) ? -xvel : xvel);  // x vel       vels[i+2] = (float)((Math.random(  )<0.5) ? -zvel : zvel);// z vel       vels[i+1] = (float)(Math.random(  ) * Y_VELOCITY); y vel             // unchanging accelerations, downwards in y direction       accs[i] = 0.0f; accs[i+1] = -GRAVITY; accs[i+2] = 0.0f;           // initial particle color is yellow       cols[i] = yellow.x;  cols[i+1] = yellow.y; cols[i+2] = yellow.z;     } 

The method initializes the cs[], vels[], accs[], and cols[] arrays.

The x-axis velocity is randomly set between -XZ_VELOCITY and XZ_VELOCITY, and the z-axis velocity is assigned the value that makes the magnitude of the combined XZ vector equal XZ_VELOCITY. This means that particles can travel in any direction across the XZ plane, but they all have the same speed.

The only acceleration is a constant, gravity down the y-axis. By including accelerations in the x-and z-directions, forces such as air resistance could be simulated as well.

createAppearance( ) increases the point size of the particles:

     private void createAppearance(  )     { Appearance app = new Appearance(  );       PointAttributes pa = new PointAttributes(  );       pa.setPointSize( POINTSIZE );  // may cause bugs       app.setPointAttributes(pa);       setAppearance(app);     } 

Point size adjustment, point anti-aliasing, line size adjustment, and line anti-aliasing are poorly supported in Java 3D because of weaknesses in the underlying graphics libraries and/or drivers. Currently, OpenGL and OpenGL-compatible graphics cards can cope, but DirectX-based system often crash.

Updating the Points

The PointsUpdater class utilizes updateData( ) differently than outlined earlier:

     public void updateData(Geometry geo)     { // GeometryArray ga = (GeometryArray) geo;       // float cds[] = ga.getCoordRefFloat(  );           // step in 3's == one (x,y,z) coord       for(int i=0; i < numPoints*3; i=i+3) {         if (cs[i+1] < 0.0f)    // particle dropped below y-axis           initParticle(i);     // reinitialise it         else       // update the particle           updateParticle(i);       }     }  // end of updateData(  ) 

The commented out lines indicate that no use is made of the Geometry input argument. Instead, the float arrays (cs[], vels[], accs[], and cols[]), which are global, are accessed directly.

updateData( )'s primary purpose is to be called by Java 3D when it's safe to modify the arrays. It doesn't matter where the array references originate.


updateData( ) implements particle reuse by detecting when a particle has dropped below the y-axis and then reinitializing it by calling PointParticles's initParticle( ) method. This shows the advantage of using an inner class and global float arrays.

Updating Particles

Underpinning the motion of the particles is Newton's second law, which relates force (F) to mass (m) and acceleration (a):

F = ma

I can make this simpler by assuming that a particle has a mass of one unit:

F = a

In other words, the only force on a particle is constant acceleration, which is gravity for the examples in this chapter.

It's possible to obtain velocity and distance equations from this basic assumption by using Euler's integration algorithm. The acceleration equation can be written as:

d vel/dt = a

or:

d vel = a dt

Using Euler's method, you can obtain the velocity equation:

vel(t + dt) = vel(t) + a dt

Integrating again:

The equations can be separated into their x-, y-, and z-components. For example:

velx(t+dt) = velx(t) + ax dt
distx(t+dt) = distx(t) + velx(t) dt + 1/2 ax dt2

These equations are embedded in the updateParticle( ) method, where distx, disty, and distz are cs[i] to cs[i+2], and velx, vely, and velz are vels[i] to vels[i+2]:

     private void updateParticle(int i)     { cs[i] += vels[i] * TIMESTEP +                 0.5 * accs[i] * TIMESTEP * TIMESTEP;     // x coord       cs[i+1] += vels[i+1] * TIMESTEP +                 0.5 * accs[i+1] * TIMESTEP * TIMESTEP;  // y coord       cs[i+2] += vels[i+2] * TIMESTEP +                 0.5 * accs[i+2] * TIMESTEP * TIMESTEP;  // z coord           vels[i] += accs[i] * TIMESTEP;      // x vel       vels[i+1] += accs[i+1] * TIMESTEP;  // y vel       vels[i+2] += accs[i+2] * TIMESTEP;  // z vel           updateColour(i);     } // end of updateParticle(  ) 

The small time step, dt, is fixed as the constant TIMESTEP (0.05f).

updateColor( ) reduces the green and blue components of a point's color. Over time, these will drop to 0, leaving only red:

     private void updateColour(int i)     { cols[i+1] = cols[i+1] - FADE_INCR;   // green part       if (cols[i+1] < 0.0f)         cols[i+1] = 0.0f;       cols[i+2] = cols[i+2] - FADE_INCR;   // blue part       if (cols[i+2] < 0.0f)         cols[i+2] = 0.0f;     } 

Triggering an Update

The ParticlesControl behavior requests an update to the PointArray every few milliseconds:

     public class PartclesControl extends Behavior     { private WakeupCondition timedelay;       private PointsUpdater updater;           public PartclesControl(int delay, PointsUpdater updt)       {  timedelay = new WakeupOnElapsedTime(delay);          updater = updt;       }           public void initialize( )       { wakeupOn( timedelay );  }           public void processStimulus(Enumeration criteria)       { pointParts.updateData(updater);  // request update of geometry         wakeupOn( timedelay );       }     }  // end of PartclesControl class 

This behavior is almost the same in each of the particle system classes: only the types of the GeometryArray and GeometryUpdater arguments change.



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