Can anyaone test this please?

hi,

i’ve a small problem, i’ve made a simple particle system where the particles should fade, but they don’t. To be sure it’s not a software or hardware problem, could one of you be kind enough to test this class?


package spacerace.core;

import java.util.Enumeration;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.geometry.*;


// TODO: optimizations possible, biggest one is checking if there are still particles "alive",
// second one to update just the right ones

/**
 * A burst are particles thrown in a direction and fading with time. It is usually
 * used to represent the flames of a propulsion system (in particular for the ships).
 * To have more advanced effects, many different bursts can be added together.
 */
class Burst extends BranchGroup
{
      // behavior responsible for creating and recycling the particles
      protected ParticlesCreator particlesCreator;
      // behavior responsible for particles state
      protected ParticlesUpdater particlesUpdater;

      // The position where the new particles are thrown from
      Tuple3f pos;
      // The direction in which the new particles are thrown
      Vector3f direction;
      // number of particles thrown per second
      protected int intensity;
      //the time in milliseconds taken for any particle to become totally transparent.
      protected long fadingTime;

      // the array of point particles
      protected PointArray particles;
      // the start position of each particle
      protected Tuple3f[] startPos;
      // the velocity of each particle
      protected Tuple3f[] velocity;
      // when the particle was thrown
      protected long[] startTime;

      /**
       * Creates a red burst with default values (intensity = 100, fading time = 1000 ms).
       */
      Burst ()
      {
            this(new Color3f(1,0,0), 100, 1000);
      }

      /**
       * Creates a burst of given color, intensity and fading time.
       *
       * @param      color - the burst color
       * @param      intensity - number of particles thrown per second
       * @param      fadingTime - the time in milliseconds taken for any particle to become totally transparent.
       */
      Burst(Color3f color, int intensity, long fadingTime)
      {
            this.intensity = intensity;
            this.fadingTime = fadingTime;

            // The +1 is to round up
            int nbParticles = (int) (intensity * fadingTime) / 1000 + 1;

            // Create the data
            startPos = new Tuple3f[nbParticles];
            for (int i=0; i<startPos.length; i++)
                  startPos[i] = new Vector3f();

            velocity = new Tuple3f[nbParticles];
            for (int i=0; i<velocity.length; i++)
                  velocity[i] = new Vector3f();
            startTime = new long[nbParticles];

            float[] coords = new float[nbParticles*4];

            float[] colors = new float[nbParticles*4];
            for (int i=0; i<nbParticles ; i++)
            {
                  colors[4*i+0] = color.x;
                  colors[4*i+1] = color.y;
                  colors[4*i+2] = color.z;
                  colors[4*i+3] = 1;
            }

            // Create the particles
            particles = new PointArray(nbParticles, GeometryArray.COORDINATES | GeometryArray.COLOR_4 | GeometryArray.BY_REFERENCE);

            particles.setCapability(GeometryArray.ALLOW_REF_DATA_WRITE);
            particles.setCapability(GeometryArray.ALLOW_REF_DATA_READ);
            particles.setCapability(GeometryArray.ALLOW_COUNT_READ);

            particles.setCoordRefFloat(coords);
            particles.setColorRefFloat(colors);

            // Create the particles creator
            particlesCreator = new ParticlesCreator();
            particlesCreator.setSchedulingBounds(new BoundingSphere(new Point3d(), Double.MAX_VALUE));

            // Create the particles updater
            particlesUpdater = new ParticlesUpdater();
            particlesUpdater.setSchedulingBounds(new BoundingSphere(new Point3d(), Double.MAX_VALUE));

            // Add them all
            this.addChild(new Shape3D(particles));
            this.addChild(particlesCreator);
            this.addChild(particlesUpdater);
      }



      /**
      * Turns the burst on, while continuing to update older particles.
      */
      public void activate()
      {
            particlesCreator.setEnable(true);
      }


      /**
       * Turns the burst off, while continuing to update existing particles.
       */
      public void deactivate()
      {
            particlesCreator.setEnable(false);
      }


       /**
        * This is the behavior responsible for creating and recycling the particles.
        */
       class ParticlesCreator extends Behavior
      {
            private WakeupCriterion wakeupCondition;
            private int newParticleIndex = 0;

            ParticlesCreator()
            {
                  wakeupCondition = new WakeupOnElapsedTime((int) (1000f / intensity));
            }

            public void initialize()
            {
                  this.wakeupOn(wakeupCondition);
            }

            /**
             * Creates/recycles a particle.
             */
            public void processStimulus(Enumeration criteria)
            {
                  // select the next particle index
                  newParticleIndex++;
                  if (newParticleIndex == particles.getValidVertexCount())
                        newParticleIndex = 0;

                  // set its start position as the current position
                  startPos[newParticleIndex].set(pos);

                  // set its velocity in the current randomly altered direction
                  float L = direction.length();
                  velocity[newParticleIndex].set(
                        direction.x + L*(float)(Math.random()-0.5),
                        direction.y + L*(float)(Math.random()-0.5),
                        direction.z + L*(float)(Math.random()-0.5)
                  );

                  // set its throwing time
                  startTime[newParticleIndex] = System.currentTimeMillis();

                  this.wakeupOn(wakeupCondition);
            }
      }

      /**
       * This updates the position and the velocity of particles based on their values
       * and the elapsed time.
       */
      class ParticlesUpdater extends Behavior implements GeometryUpdater
      {
            private WakeupCriterion wakeupCondition = new WakeupOnElapsedFrames(0);

            public void initialize()
            {
                  this.wakeupOn(wakeupCondition);
            }

            /**
             * Updates the particles state.
             */
            public void processStimulus(Enumeration criteria)
            {
                  particles.updateData(this);
                  this.wakeupOn(wakeupCondition);
            }

            /**
             * Called by the geometry updater to perform updating.
             */
            public void updateData(Geometry geo)
            {
                  // get the data
                  PointArray pa = (PointArray) geo;
                  int n = pa.getValidVertexCount();
                  float[] coords = pa.getCoordRefFloat();
                  float[] colors = pa.getColorRefFloat();

                  long currentTime = System.currentTimeMillis();

                  for (int i=0; i<n; i++)
                        if (startTime[i] > 0)      // if particle is alive
                        {
                              // compute the delay between now and when the particle was created
                              long dt_ms = currentTime - startTime[i];
                              float dt_s = (float) dt_ms / 1000;

                              // update the coordinates
                              coords[3*i+0] = startPos[i].x + velocity[i].x * dt_s;
                              coords[3*i+1] = startPos[i].y + velocity[i].y * dt_s;
                              coords[3*i+2] = startPos[i].z + velocity[i].z * dt_s;

                              // update the color
                              colors[4*i+3] = (float) dt_ms/fadingTime;

                              // if particle has finished its life cycle
                              if (dt_ms >= fadingTime)
                              {
                                    startTime[i] = -1; // no more alive
                                    colors[4*i+3] = 1; // make it totally transparent
                              }
                        }

            }
      }

      /**
       * Shows a burst.
       */
      public static void main(String[] args)
      {
            SimpleUniverse u = new SimpleUniverse();

            u.getViewingPlatform().setNominalViewingTransform();

            Burst burst = new Burst(new Color3f(0,1,1), 100, 2000);
            burst.pos = new Vector3f();
            burst.direction = new Vector3f(0.25f,0,0);

            BranchGroup bg = new BranchGroup();
            bg.addChild(burst);
            bg.compile();

            u.addBranchGraph(bg);
      }
}

thanks in advance.

edit: “simple particle system” are maybe words that don’t go together! :stuck_out_tongue:

A small scatter of blue points flies from left to right. After a short duration each point vanishes. There is no perceptible change in their appearance before they vanish.

The A in RGBA stands for Alpha and not Transparency ;), if you want your particles to fade. So modify your settings for Alpha as follows:

colors[4*i+3] = 1.f - (float) dt_ms/fadingTime;

and

colors[4*i+3] = 0; // make it totally transparent

Then create a new Appearance and set it on your Shape3D with a PointAttributes with setPointAntialiasingEnable(true). This will (also) provide the transparent effect.

With the above mods I see the nice effect that you’re after.

thanks man! ;D

hmm… i was talking too quick… i made the changes, also changed the point size to “see” the PointAttributes were correctly set. But still no transparency…
After looking aroud a bit, i figured out that the DX version (what i have :P) may simply not have point antialiasing feature.

I tested it on the OpenGL version, though.

[quote]hmm… i was talking too quick… i made the changes, also changed the point size to “see” the PointAttributes were correctly set. But still no transparency…
After looking aroud a bit, i figured out that the DX version (what i have :P) may simply not have point antialiasing feature.
[/quote]
If PointAA doesn’t work, try setting a TransparencyAttributes() on the appearance with a transparency of, say, 0.6f and see how it goes…

But without PointAA your particles will lose much of their visual appeal !

Edit: And did I say that before ? works nicely for me with the mods on WinOGL Java 3D.

thanks for feedback. i wonder how they fade on OGL ::slight_smile: :stuck_out_tongue:
but since it won’t work here, i simply not make they die (removing the ‘startTime[i] = -1;’). Doing this, it looks ok in DX version and i guess even better on GL! :wink: