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!