Theres a easier way to do it with the particle effect, you just have to use the Fog Machine as sample
you can see it in my video at 0:43:
this is how particle system looks:
package particleengine;
import nlvm.lang.*;
import nlvm.math3d.*;
public class ParticleEmitter extends PhysicalObject
{
    private ParticleList _ParticlePool;
    private ParticleList _ParticleList;
    private ParticleManager _Manager;
    private float _sumTimeSteps;
    public Vector3f EmitterDirection;
    public Vector3f ParticleGravity = new Vector3f();
    public float ParticleAirResistance = 0;
    public float ParticlesPerSecond = 1;
    public float ParticleInitialVelocity;
    public float ParticleTimeToLive = 2;
    public float ParticleMass = 1;
    public float ParticleRotationSpeed = 0;
    public bool  ParticleRotationRandomStartAngle = false;
    public bool  ParticleRotationRandomDirection = false;
    public float ParticleStartScale = 1;
    public float ParticleEndScale = 1;
    public float ParticlePositionJitterX = 0;
    public float ParticlePositionJitterY = 0;
    public float ParticlePositionJitterZ = 0;
    
    // Alpha Controls
    public float FadeInDuration = 0;
    public float FadeOutDuration = 0;
    public float Opacity = 1;
    public bool Enabled = false;
    
    // Create a new particle emitter.
    public ParticleEmitter(ParticleManager manager, ParticleList pool)
    {
        _Manager = manager;
        _ParticlePool = pool;
        _ParticleList = new ParticleList();
       
        EmitterDirection = new Vector3f();
    }
    
    public void SetEmitterDirection(float x, float y, float z)
    {
        EmitterDirection.x = x;
        EmitterDirection.y = y;
        EmitterDirection.z = z;
    }
    // Take a free particle from the pool and fire it out the emitter.
    public void GenerateParticle()
    {
        if (_ParticlePool.IsEmpty())
        {
            return;
        }
        // get the first particle from the pool and attach it to the emitter's list
        Particle particle = _ParticlePool.First();
        _ParticleList.InsertFront(particle);
        
        // make sure emitter direction vector is normalized, or else initial velocity will be wrong
        float L = (float)Math.sqrt(EmitterDirection.x*EmitterDirection.x + EmitterDirection.y*EmitterDirection.y + EmitterDirection.z*EmitterDirection.z);
        EmitterDirection.x /= L;
        EmitterDirection.y /= L;
        EmitterDirection.z /= L;
        
        // set particle parameters
        particle.EffectTime = 0;        
        particle.Gravity = ParticleGravity;
        particle.AirResistance = ParticleAirResistance;
        particle.TimeToLive = ParticleTimeToLive;
        particle.Mass = ParticleMass;
        particle.Velocity.x = EmitterDirection.x * ParticleInitialVelocity;
        particle.Velocity.y = EmitterDirection.y * ParticleInitialVelocity;
        particle.Velocity.z = EmitterDirection.z * ParticleInitialVelocity;
        particle.Position.x = Position.x;
        particle.Position.y = Position.y;
        particle.Position.z = Position.z;
        particle.FadeInDuration = FadeInDuration;
        particle.FadeOutDuration = FadeOutDuration;
        particle.Opacity = Opacity;
        particle.StartScale = ParticleStartScale;
        particle.EndScale = ParticleEndScale;
        particle.PositionJitterX = (float)Math.random() * ParticlePositionJitterX;
        particle.PositionJitterY = (float)Math.random() * ParticlePositionJitterY;
        particle.PositionJitterZ = (float)Math.random() * ParticlePositionJitterZ;
        
        if (ParticleRotationRandomStartAngle)
        {
          particle.RandomStartAngle = (float)(2 * Math.PI * Math.random());
        }
        else
        {
          particle.RandomStartAngle = 0;
        }
        
        if (ParticleRotationRandomDirection)
        {
          particle.RotationSpeed = Math.random() > 0.5 ? ParticleRotationSpeed : -ParticleRotationSpeed;
        }
        else
        {
          particle.RotationSpeed = ParticleRotationSpeed;
        }
        
        particle.SetVisible(true);
    }
    
    public void Update(float timeStep)
    {
        super.Update(timeStep);
        if (Enabled)
        {
            if (ParticlesPerSecond > 0)
            {
                _sumTimeSteps += timeStep;
                float timeBetweenParticles = (ParticlesPerSecond > 1000) ? 0.001f : (1.0f / ParticlesPerSecond);
                while (_sumTimeSteps > timeBetweenParticles)
                {
                    GenerateParticle();
                    _sumTimeSteps -= timeBetweenParticles;
                }
            }
        }
        // update all particles owned by the emitter
        Particle particle = _ParticleList.First();
        while(particle != null)
        {
            Particle nextParticle = particle.Next;
            particle.Update(timeStep);
            particle = nextParticle;
        }
    }
}
Here are the mains option you can edit to change the effect:
public Vector3f EmitterDirection;
    public Vector3f ParticleGravity = new Vector3f();
    public float ParticleAirResistance = 0;
    public float ParticlesPerSecond = 1;
    public float ParticleInitialVelocity;
    public float ParticleTimeToLive = 2;
    public float ParticleMass = 1;
    public float ParticleRotationSpeed = 0;
    public bool  ParticleRotationRandomStartAngle = false;
    public bool  ParticleRotationRandomDirection = false;
    public float ParticleStartScale = 1;
    public float ParticleEndScale = 1;
    public float ParticlePositionJitterX = 0;
    public float ParticlePositionJitterY = 0;
    public float ParticlePositionJitterZ = 0;