Page 1 of 2

Particle systems revisited

Posted: 28.10.2009, 15:01
by chris
Continuing discussons begun in this thread: viewtopic.php?f=9&t=14419&st=0&sk=t&sd=a&start=45

The following four videos show what is possible with particle systems in Celestia:

Ion engine thrust:
http://www.youtube.com/watch?v=S5JgkD3H_Ac

Eruption of Tvashtar:
http://www.youtube.com/watch?v=fHj4jcmGRDY

Meteor:
http://www.youtube.com/watch?v=O72u4Jxb2No

Liftoff (Buran model by Runar, Baikonur by Linuxm@n):
http://www.youtube.com/watch?v=3_JFktYSMTE

These are experiments that I made about a year ago. The Tvashtar example is using about 10000 particles (if I recall correctly), and Celestia still runs quite smoothly. With some optimization, systems with a million particles should be possible.

Each particle is assigned an initial position and velocity with some distribution that may be specified in the particle system definition file. The particles are affected by a constant force, so the resulting motion is either parabolic or linear (when the force is zero.) Completely static particle systems are also possible; for example, the ion thrust would look more realistic if the animation were frozen.

--Chris

Re: Particle systems revisited

Posted: 28.10.2009, 15:27
by Cham
Also this volcanic example (test 2) :
http://www.youtube.com/watch?v=nJqkdbkO ... re=related

Chris,

is it possible to extend the code to include a constant force, oriented at 90° to the velocity ? This would allow circular motion as well (accretion disk, for example).

EDIT : Also, could you describe in detail how is the data file should be defined (input file) ?

I think that part of the discussion from the ScriptedOrbit thread could be pasted here...

Re: Particle systems revisited

Posted: 28.10.2009, 15:41
by Cham
Here's a reply from the ScriptedOrbit thread, which I think it relevant to the discussion here :

chris wrote:As currently implemented, the motion of a particle in particle system must be expressible as a parametric quadratic curve. Is this adequate for your examples?

What do you mean by "quadratic curve" ? Do you mean a simple polynomial of degree 2 ? If yes, this is pretty limited. At least, the jets and volcano I made are quadratic :

The volcano CELXX code I'm using :

Code: Select all

function parabolic_motion(t)
   local orbit = {};
   orbit.params = t;
   orbit.boundingRadius = 2 * t.InitialRadius

   local RandomVelocity = t.MinVelocity + (t.MaxVelocity - t.MinVelocity) * math.random();
   local Delta = math.rad(t.MinDeclination + (t.MaxDeclination - t.MinDeclination) * math.random());
   local Phi = 2 * math.pi * math.random();

   local MaxTime = 2.1 * RandomVelocity * math.sin(Delta)/(86400 * t.Gravity);
   local RandomDelay = MaxTime * math.random();

    function orbit:position(tjd)
   local t = tjd - 2451545.0

   local Alpha = math.rad(self.params.Longitude);
   local Beta  = math.rad(self.params.Latitude);

   local CyclicTime = (t - RandomDelay) - MaxTime * math.floor((t - RandomDelay) / MaxTime)

   local acct  = 3732480 * self.params.Gravity * CyclicTime * CyclicTime;
   local v0xt  = 86.4 * RandomVelocity * math.cos(Delta) * math.cos(Phi) * CyclicTime;
   local v0yt  = 86.4 * RandomVelocity * math.cos(Delta) * math.sin(Phi) * CyclicTime;
   local v0zt  = 86.4 * RandomVelocity * math.sin(Delta) * CyclicTime;

   local x = (self.params.InitialRadius + v0zt - acct) * math.cos(Beta) * math.cos(Alpha) - v0xt * math.sin(Beta) * math.cos(Alpha) + v0yt * math.sin(Alpha)
   local y = (self.params.InitialRadius + v0zt - acct) * math.cos(Beta) * math.sin(Alpha) - v0xt * math.sin(Beta) * math.sin(Alpha) - v0yt * math.cos(Alpha)
   local z = (self.params.InitialRadius + v0zt - acct) * math.sin(Beta) + v0xt * math.cos(Beta)

   return x, y, z
    end

    return orbit
end


The jets code (a trivial variation of the previous one) :

Code: Select all

function jet_motion(t)
   local orbit = {};
   orbit.params = t;
   orbit.boundingRadius = 2 * t.InitialRadius

   local v0 = 86.4 * (t.MinVelocity + (t.MaxVelocity - t.MinVelocity) * math.random());
   local Delta = math.rad(t.MinDeclination + (t.MaxDeclination - t.MinDeclination) * math.random());
   local MaxTime = 0.9 * v0 * math.sin(Delta)/(7464960 * t.Deceleration);
   local RandomDelay = MaxTime * math.random();
   local Phi = 2 * math.pi * math.random();

    function orbit:position(tjd)
   local t = tjd - 2451545.0

   local PeriodicTime = (t - RandomDelay) - MaxTime * math.floor((t - RandomDelay) / MaxTime);

   local x = v0 * math.cos(Delta) * math.cos(Phi) * PeriodicTime
   local y = v0 * math.cos(Delta) * math.sin(Phi) * PeriodicTime
   local z = self.params.Pole * (self.params.InitialRadius + v0 * math.sin(Delta) * PeriodicTime - 3732480 * self.params.Deceleration * PeriodicTime * PeriodicTime)

   return x, y, z
    end

    return orbit
end


In the case of the jets, the SSC code defines the input data. Here's an example for a single particle :

Code: Select all

"Particle 1" "Black Hole experiment"
{
   Class "diffuse"
   Mesh "blob4_sprites.cmod"
   Emissive true
   Radius 25000

   ScriptedOrbit {
      Module "jet_motion"
      Function "jet_motion"

      InitialRadius   20000   # Altitude of the launch point, in km
      Pole      1   # Starting pole.  Must be 1 or -1
      MinVelocity   4E7   # Minimal launch velocity, in m/s
      MaxVelocity   4.25E7   # Maximal launch velocity, in m/s
      MinDeclination   85   # Minimal initial velocity declination, in degrees
      MaxDeclination   90   # Maximal initial velocity declination, in degrees
      Deceleration   700000   # Deceleration effect, in m/s^2
   }
}



The curves in these two examples are just quadratic polynomials of the time variable (actually a periodic version of time, defined using the "floor" function), with several angles and velocity parameters as input :

equs.jpg

Here, [tex]\beta[/tex] and [tex]\alpha[/tex] are respectively the Latitude and Longitude of the source. The initial velocity ([tex]v_{0 x}[/tex], [tex]v_{0 y}[/tex] and [tex]v_{0 z}[/tex]) is a random vector which depend on [tex]v_{0}[/tex] (random modulus [tex]v_0 \in [v_{0 min}, v_{0 max} ][/tex]), the declination (random value [tex]\delta \in [\delta_{min}, \delta_{max}][/tex]) and the azimuth (random variable [tex]\phi \in [0, 2 \pi[[/tex]) :
[tex]v_{0 x} = v_{0} \cos\delta \cos\phi[/tex],
[tex]v_{0 y} = v_{0} \cos\delta \sin\phi[/tex],
[tex]v_{0 z} = v_{0} \sin\delta[/tex].

In the case of time, I made it cyclic, using the "floor" function :
[tex]CyclicTime = \tau(t) = t - t_0 - T floor(\frac{t - t_0}{T})[/tex],

where [tex]t_0 \in [0, T][/tex] is a random delay and [tex]T[/tex] is the period of the whole motion.

Chris,

in the case of solar flares, we need more than quadratic functions. For example, a deformation of a circle :
[tex]x(t) =R + a \sin(\omega t + \phi)[/tex]
[tex]y(t) = b \cos(\omega t + \phi)[/tex]
[tex]z(t) = 0[/tex]

This would also be usefull to make accretion disks, with hopefully turbulence and/or differential rotation....

Re: Particle systems revisited

Posted: 28.10.2009, 16:27
by chris
Cham wrote:Also this volcanic example (test 2) :
http://www.youtube.com/watch?v=nJqkdbkO ... re=related

Chris,

is it possible to extend the code to include a constant force, oriented at 90° to the velocity ? This would allow circular motion as well (accretion disk, for example).

Whatever the forces chosen, we ultimately need a closed-forum solution for the motion of the particle: the user has free control over the time in Celestia, so we can't use numerical integration to compute the path of the particle. So, circular motion is certainly a possibility. Simpler expressions for particle motion are better, because they may be evaluated millions of times per second. General Keplerian motion from a 1/r^2 central force is probably a bit much, but the special case of circular motion is simple enough (and probably would cover the great majority of usage scenarios for particle systems.)

Also, could you describe in detail how is the data file should be defined (input file) ?

I could, but I'm not so sure it's worthwhile. The reason that I haven't enabled particle systems in Celestia is because I wasn't satisfied with the file format. Better to develop something starting with this thread, I think.

--Chris

Re: Particle systems revisited

Posted: 28.10.2009, 17:53
by Cham
chris wrote:
Also, could you describe in detail how is the data file should be defined (input file) ?
I could, but I'm not so sure it's worthwhile. The reason that I haven't enabled particle systems in Celestia is because I wasn't satisfied with the file format. Better to develop something starting with this thread, I think.

Furious and blind brainstorm :
Ok. I don't know how your animation code was done, but I suggest to define the input data in some "standard" SSC way (also STC, hopefully), like what I've done with the ScriptedOrbit models (with maybe some data file to be placed in the data folder) :

Code: Select all

"Jets" "Black Hole"
{
   Class "animation" <------- Some new classes ? *** see below ***
   Emissive true  <------- ??

   ParticleAnimation {  <------- New ?
      Module "jet_motion" <--------- the code file to be found in the data folder ?
      Function "jet_motion"  <------ function in the code file ?

      InitialRadius   20000   # Altitude of the launch point, in km
      Longitude      45   # Source location, in degrees
      Latitude      45   # Source location, in degrees
      MinVelocity   4E7   # Minimal launch velocity, in m/s
      MaxVelocity   4.25E7   # Maximal launch velocity, in m/s
      MinDeclination   85   # Minimal initial velocity declination, in degrees
      MaxDeclination   90   # Maximal initial velocity declination, in degrees
      Deceleration   700000   # Deceleration effect, in m/s^2  <-------- constant "force"
   }
}


Of course, the parameters listed in the SSC should match the code file located in the data folder (which is a LUA file in the CELXX directory, in the case of my ScriptedOrbit addons).

However, maybe we don't need the code file (in the data folder), if the particles system code is included in Celestia itself (for optimisation purposes ?). Given a specific class (*** see above ***), we just need to use the same base parameters declaration in the SSC code, with a reference to the class used : a "parabolic class" for the quadratic curves, a "circular class" for circular animation, etc. In other words, the class name tells Celestia what kind of particles animation we are using in the SSC.

EDIT : Hmmm, maybe the new classes are unecessary. The particles system name should be declared in the line "ParticleAnimation { <------- New ?" instead.

In the case of a quadratic curve, there isn't much parameters to be declared :

- starting point (three coordinates),
- Initial velocity (modulus and orientation),
- acceleration (modulus and orientation),
- a period ?
so 10 parameters as input data. Some may be random, so undeclared in the SSC.

Is there something I'm forgetting ? "Randomisation" parameters ?

EDIT : It is clear that I could define the CELXX volcano and jets using exactly the same LUA and SSC code, by declaring some standard parameters (see the examples I gave in the ScriptedOrbit thread). So I'm sure there's a simple and general enough way to define a particles system, in the case of a constant acceleration. However, the circular motion needs an independant treatment, since there's a constraint on the acceleration (relative to the velocity). This is why I suggest to use different names in the line "ParticleAnimation { <------- New ?"

All this stuff is really about the implicit maths used under the particles effect...

Re: Particle systems revisited

Posted: 28.10.2009, 18:17
by chris
Cham wrote:
chris wrote:
Also, could you describe in detail how is the data file should be defined (input file) ?
I could, but I'm not so sure it's worthwhile. The reason that I haven't enabled particle systems in Celestia is because I wasn't satisfied with the file format. Better to develop something starting with this thread, I think.

Furious and blind brainstorm :
Ok. I don't know how your animation code was done, but I suggest to define the input data in some "standard" SSC way (also STC, hopefully), like what I've done with the ScriptedOrbit models (with maybe some data file to be placed in the data folder) :

The cleanest way to add particle system support is to create a type of model file. This way, the SSC file format doesn't need to be complicated, and particle systems will work for any object that uses a model file. To use a particle system, you'd just specify a particle system file with Mesh property:

Code: Select all

SurfaceObject "Tvashtar" "Sol/Jupiter/Io"
{
    Radius 200
    Mesh "plume.cpart"

    FixedPosition { Planetocentric [ 123.53 62.76 0 ] }
    ...etc...
}


It's the format of the particle system definition file that needs to be decided. I agree that it would be good to use a structure similar to what we currently have with SSC files.

--Chris

Re: Particle systems revisited

Posted: 28.10.2009, 18:25
by Cham
chris wrote:To use a particle system, you'd just specify a particle system file with Mesh property:

Code: Select all

SurfaceObject "Tvashtar" "Sol/Jupiter/Io"
{
    Radius 200
    Mesh "plume.cpart"

    FixedPosition { Planetocentric [ 123.53 62.76 0 ] }
    ...etc...
}


Aaah! Yes, I agree with this. A new kind of "mesh" seems to be very good ! I guess that the actual .cpart file would be internal to Celestia (hard coded into the application itself) ? Maybe a code file located in the models directory ?

So if I understand you correctly, the main problem is the list of parameters to be declared in the SSC code ?

EDIT : Aaargh ! I just realised that the number of particles, color and opacity variations may also be another thing to add, in the parameters list... And there's also the size of the particles. I was defining all these in the CMOD file, not in the SSC file, while the number of particles is declared as many SSC declarations ! For a particles system, this may make the SSC declaration more complicated :?

So I need to know where the new code files would be located ? Hard coded in the application itself, or as .cpart files in the models folder ?

Re: Particle systems revisited

Posted: 28.10.2009, 21:04
by chris
Cham wrote:Aaah! Yes, I agree with this. A new kind of "mesh" seems to be very good ! I guess that the actual .cpart file would be internal to Celestia (hard coded into the application itself) ? Maybe a code file located in the models directory ?

It would be a text file located in the models directory, and it would contain all of the particle system parameters.

So if I understand you correctly, the main problem is the list of parameters to be declared in the SSC code ?

EDIT : Aaargh ! I just realised that the number of particles, color and opacity variations may also be another thing to add, in the parameters list... And there's also the size of the particles. I was defining all these in the CMOD file, not in the SSC file, while the number of particles is declared as many SSC declarations ! For a particles system, this may make the SSC declaration more complicated :?

So I need to know where the new code files would be located ? Hard coded in the application itself, or as .cpart files in the models folder ?

On second thought, maybe it is best to show one of the particle system files used in the examples, just to give a rough idea of how things might work. Here's the Tvashtar plume:

Code: Select all

Emitter
{
    Texture "blob.jpg"
    StartColor [ 0.04 0.35 0.7 ]
    EndColor [ 0 0 0 ]

    StartSize 0.01
    EndSize 0.05

    Rate 100
    Lifetime 30

    InitialPosition { Constant [ 0 0 0 ] }
    InitialVelocity { Cone { MaxAngle 30 MinSpeed 0.04 MaxSpeed 0.08 } }

    Acceleration [ 0 0 -0.003 ]
}

  • The particle system files contains one or more emitters.
  • Particles are created at Rate times per second and they last for Lifetime seconds before disappearing. This means that there the number of particles for a particular emitter will be Rate * Lifetime.
  • The particle's size is interpolated from StartSize to EndSize over its lifetime.
  • The particle's color is interpolated from StartColor to EndColor over its lifetime.
  • InitialPosition and InitialVelocity give the distribution of initial positions and velocities. There are several different types available, the simplest being Constant.
  • Acceleration is a vector in the local coordinate system of the particle system.
  • Not shown here, but explosions and such can be created with particle systems that have a finite lifetime, with a start and end time given as an offset in seconds from the Beginning time defined in the ssc file.

Some of these ideas work well, others not so much. The biggest problem I have is with the initial position and velocity distributions. The scheme I invented for defining them is sort of clunky, though it's not too awful for the plume example. The ability to give the initial position and velocity distributions separately allows for a lot of flexibility, but most of the combinations are not interesting, and it makes the common cases more cumbersome than they should be. Please consider the above example to be at best a very rough draft.

--Chris

Re: Particle systems revisited

Posted: 28.10.2009, 23:52
by Fenerit
Within the InitialVelocity block is specifyied "cone", being it, whether I'm not wrong, the "bounding shape" in which the particles insist and spreads off; I suppose there will be other shapes (sphere, cylinder, etc..). Now I wonder whether calling it, say, "custom" would be possible to add here and in this way the link at the quadratic functions, following the ScriptedOrbit method; that is, to state in a LUA module the path of the particles, allowing more complex figures.

Re: Particle systems revisited

Posted: 29.10.2009, 18:20
by chris
Fenerit wrote:Within the InitialVelocity block is specifyied "cone", being it, whether I'm not wrong, the "bounding shape" in which the particles insist and spreads off; I suppose there will be other shapes (sphere, cylinder, etc..). Now I wonder whether calling it, say, "custom" would be possible to add here and in this way the link at the quadratic functions, following the ScriptedOrbit method; that is, to state in a LUA module the path of the particles, allowing more complex figures.

Scriptable initial state is possible, but not desirable: the whole point is for particle systems to be fast. I'd rather work to develop a set of fast, built-in initial state generators that cover 99% of usage scenarios.

--Chris

Re: Particle systems revisited

Posted: 29.10.2009, 18:24
by Cham
chris wrote:It would be a text file located in the models directory, and it would contain all of the particle system parameters.

Chris,

if there will be different "model" .cpart files placed in the models directory, editable using a text editor, I think that the parameters declared in the SSC should be fully customisable by the user, like what we currently do with the ScriptedOrbit method. So all the initial conditions (input data) could take any form, depending of what the user want to do with his/her .cpart file.

Is that possible ?

EDIT : Hmmm, cross-posting.

How many **general** parameters need to be declared for a quadratic curve ? 10 ? Plus the particle's size, color and opacity parameters ?

Re: Particle systems revisited

Posted: 29.10.2009, 22:54
by Fenerit
Summing up:

1) the SSC file act as usual, set out "where" the emitter/s is, and it could be also in motion thanks to the ScriptedOrbit method;
2) the .CPART file will hold all the emitter's settings, so that, i.e. for an explosion, one emitter could to manage the lights and the another emitter the smokes (WITHIN THE SAME .CPART);
3) needs to be well defined the emitter's parameters, right?

Re: Particle systems revisited

Posted: 30.10.2009, 18:12
by duds26
Don't like the idea of (yet) another file extension.
Please use cmod for this, since those particle's are essentially bodies.

Re: Particle systems revisited

Posted: 30.10.2009, 19:58
by Cham
duds26 wrote:Don't like the idea of (yet) another file extension.
Please use cmod for this, since those particle's are essentially bodies.

I don't agree. A new file extension for particles systems is necessary. Or else, there will be lots of confusion between the various CMOD files. And it really isn't about the same kind of beast anyway.

Re: Particle systems revisited

Posted: 30.10.2009, 20:25
by chris
Cham wrote:
duds26 wrote:Don't like the idea of (yet) another file extension.
Please use cmod for this, since those particle's are essentially bodies.

I don't agree. A new file extension for particles systems is necessary. Or else, there will be lots of confusion between the various CMOD files. And it really isn't about the same kind of beast anyway.

Exactly: they're two very different things, and that should be reflected in the file name. Tools that operate on cmod geometry are not useful for manipulating particle systems, and vice versa.

--Chris

Re: Particle systems revisited

Posted: 30.10.2009, 20:47
by chris
Cham wrote:
chris wrote:It would be a text file located in the models directory, and it would contain all of the particle system parameters.

Chris,

if there will be different "model" .cpart files placed in the models directory, editable using a text editor, I think that the parameters declared in the SSC should be fully customisable by the user, like what we currently do with the ScriptedOrbit method. So all the initial conditions (input data) could take any form, depending of what the user want to do with his/her .cpart file.

Is that possible ?

I guess I was thinking that all the parameters would be inside the cpart file. The SSC definition would just position and orient the particle system using the standard frames, trajectories, and rotation models used for other models. I don't see a need to have user-defined SSC parameters like we do for ScriptedOrbit. If you want the particle system to behave differently, just create a different cpart file. Can you envision a scenario in which this scheme falls apart?

EDIT : Hmmm, cross-posting.
How many **general** parameters need to be declared for a quadratic curve ? 10 ? Plus the particle's size, color and opacity parameters ?
[/quote]

Just 9 parameters in three dimensions. But keep in mind that we're not specifying the parameters of the quadratics directly: the particle system parameters describe pseudorandom distributions of the initial particle state. There are many more than 9 possibilities. For example in the ion thruster example, the starting position of the particles is a Gaussian disc; parameters describe the radius and variance. Also, there are emitter-global parameters: acceleration, particle lifetime, colors, etc.

--Chris

Re: Particle systems revisited

Posted: 30.10.2009, 20:57
by Cham
chris wrote:I guess I was thinking that all the parameters would be inside the cpart file. The SSC definition would just position and orient the particle system using the standard frames, trajectories, and rotation models used for other models. I don't see a need to have user-defined SSC parameters like we do for ScriptedOrbit. If you want the particle system to behave differently, just create a different cpart file. Can you envision a scenario in which this scheme falls apart?

Ok, I agree with this. So no new parameters in the SSC, and all the system's modelisation inside the .cpart file. This makes sense. This is the way to go.

Re: Particle systems revisited

Posted: 31.10.2009, 01:41
by Fenerit
Chris, BTW, your particles examples does use the common shaders, or have one dedicated?

Re: Particle systems revisited

Posted: 31.10.2009, 09:26
by volcanopele
One change that Chris and I have discussed and that I would like to see included in particle systems, is some sort of user-definable phase function. Currently by default, Celestia assumes that objects are either emitters of light (like stars) or if they reflect light, they are back-scattering, meaning the majority of the reflected photons that bounce off an object travel back in the same direction as the light source. Celestia does have the lunar-lambert function, but this mostly treats the macroscopic roughness of an object, which effects limb darkening. For particle systems, the user should be able to define if an object is mostly back-scattering or forward scattering, meaning most of the reflected photons travel in the direction away from the light source. A few examples of well known forward-scattering particle systems include Enceladus' plume, Io's volcanic plumes, and Saturn's F, E, and G rings. In these cases, these features are much more visible when Enceladus, Io, or Saturn are visible as a crescent, and nearly invisible (particularly in the case of Enceladus' plume and many of Io's plumes) when the particle systems are viewed at low phase (sun behind the observer).

One function that could be adopted for use in the case is the Henyey-Greenstein Asymmetry function (g). Negative values for g represent back-scattering particles, and positive values for g represent forward-scattering particles. g=0 represents an isotropic surface that scatters the same amount of light at all phase angles. This setup could also be used for other objects to define how the reflectance of a surface varies with phase angle. It can be used as a single number, or as a map of some kind representing changes in g across a surface. Bjorn Jonsson did just that with Io in his own animation set up and posted a movie over at UMSF, if you want to see an example of what that can do.

Read more on the Henyey-Greenstein Asymmetry function:
http://www-loa.univ-lille1.fr/~boucher/ ... node2.html

Other Hapke photometric functions might be useful as well.

Re: Particle systems revisited

Posted: 02.11.2009, 21:33
by chris
volcanopele wrote: A few examples of well known forward-scattering particle systems include Enceladus' plume, Io's volcanic plumes, and Saturn's F, E, and G rings. In these cases, these features are much more visible when Enceladus, Io, or Saturn are visible as a crescent, and nearly invisible (particularly in the case of Enceladus' plume and many of Io's plumes) when the particle systems are viewed at low phase (sun behind the observer).

volcanopele wrote:One function that could be adopted for use in the case is the Henyey-Greenstein Asymmetry function (g). Negative values for g represent back-scattering particles, and positive values for g represent forward-scattering particles. g=0 represents an isotropic surface that scatters the same amount of light at all phase angles. This setup could also be used for other objects to define how the reflectance of a surface varies with phase angle.

I did experiment with simulating forward scattering in particle systems. See this video which shows a volcanic plume rendered with g = 0.4:

http://www.youtube.com/watch?v=nJqkdbkOTLE

The phase dependence is obvious, but it still doesn't look quite 'right'... I suspect that the value of g needs to be higher. However the problem with high values of g is that we need some mapping to the range of intensities displayable on a monitor. Here are the values of the Henyey-Greenstein phase function for g = 0.75:

0: 14.0
45: 0.615
90: 0.112
135: 0.051
180: 0.0408

When rendering to an 8-bit/channel framebuffer, if particles at 0 degrees are rendered at full-brightness, particles at 90 degrees will almost disappear. In practice, what happens is that the particles with intermediate phase angles have pixel values that are near the lowest value representable with 8-bits. Drawing lots of these particles results in very ugly quantization artifacts. I'll try and provide some more examples that illustrate this.

--Chris