TSE/Particles

From TDN

This article is a repeat of information originally posted by Jeff Faust about the changes he made to the TGEA particle system as of version 1.01, posted April 27, 2007. The original post can be seen here.

Contents

Introduction

When the TGE particle system was migrated to TGEA the developers decided, for performance reasons, to restrict particle emitters to a single render batch. Unfortunately, as first implemented, this restriction broke several existing features of particle emitters. In TGEA 1.0 you can only have one Particle per ParticleEmitter which means no multiple Particles per ParticleEmitter, no animated Particle textures, and no mixing of blend settings (useInvAlpha) in a single ParticleEmitter.

The particle system enhancements in TGEA 1.01 were added to eliminate these deficiencies and restore important capabilities to the particle system without circumventing the single render batch restriction. The end result works a little differently from the TGE particle system so some changes are required when migrating TGE particles and their assets to TGEA. This thread should help clarify what needs to be done.

The particle system enhancements in TGEA 1.01 primarily fall in three categories: 1) Added control over what portion of a texture is visible in a particle using configurable texture-coordinates. 2) Enhanced blend specification allowing all possible settings for source and destination blend factors. 3) Enhanced control over particle drawing order, including optional distance sorting.


Particle Texture Coordinates

In TGE, ParticleEmitters can mix Particles with different textures. In TGEA 1.01, multiple Particles used in a ParticleEmitter must share the same texture, but you can configure each Particle to show a different portion of the texture using texture-coordinates.

A Particle's texture-coordinates are specified using the new textureCoords field, which is a four element array where each element contains the U and V values for a corner of the Particle.

Image:Txr_coords.jpg

The default values for textureCoords show the entire texture, but by setting new texture-coordinates, you can configure a Particle to show a sub-region of the texture.

To achieve a mixed Particle effect, like what is possible in TGE, you tile together the Particle textures into a larger shared texture, and then specify each Particle's textureCoords field so that each Particle only shows one tile of the texture.

It is usually easiest to define texture-coordinates of square sub-regions of a texture, but this is not a requirement. With textureCoords, you can specify any arbitrary four-cornered region. It does not need to be square or even rectangular.

Image:Iop_tiled_goo.jpg

Here are the textureCoords for the tiles found in the above image:

// Tile A
  textureCoords[0]   = "0.0  0.5";
  textureCoords[1]   = "0.0  0.75";
  textureCoords[2]   = "0.25 0.75";
  textureCoords[3]   = "0.25 0.5";

  // Tile B
  textureCoords[0]    = "0.0 0.0";
  textureCoords[1]    = "0.0 0.5";
  textureCoords[2]    = "0.5 0.5";
  textureCoords[3]    = "0.5 0.0";

  // Tile C
  textureCoords[0]   = "0.25 0.5";
  textureCoords[1]   = "0.25 1.0";
  textureCoords[2]   = "0.65 1.0";
  textureCoords[3]   = "0.65 0.5";

  // Tile D
  textureCoords[0]   = "0.6 0.5";
  textureCoords[1]   = "0.6 1.0";
  textureCoords[2]   = "1.0 1.0";
  textureCoords[3]   = "1.0 0.5";

  // Tile E
  textureCoords[0]   = "0.0  0.75";
  textureCoords[1]   = "0.0  1.0";
  textureCoords[2]   = "0.25 1.0";
  textureCoords[3]   = "0.25 0.75";

  // Tile F
  textureCoords[0]   = "0.5 0.0";
  textureCoords[1]   = "0.5 0.5";
  textureCoords[2]   = "1.0 0.5";
  textureCoords[3]   = "1.0 0.0";

Animated Particles

As is the case in TGE, animated particles are enabled by setting the field animateTexture to true and setting framesPerSec to an appropriate frame rate. However, instead of using multiple textures, animation is done by dividing up a region of one texture into a grid of tiles with each grid cell representing one frame of animation. Column and row dimensions of the animation grid are specified with the animTexTiling field which is a two valued integer vector. Cells of the animation grid do not need to be square. Internally, frame tiles are indexed using a byte-sized value, which means that animTexTiling dimensions must specify a total of no more than 256 tiles.

The animation grid is tiled within the region specified by textureCoords using bilinear interpolation. This means that the animation tiles do not need to cover the entire texture, and they also don't need to form a perfect axis-aligned square. Animated particles can be mixed with static particles as long as they share the same texture.

The field animTexFrames is a string of frame numbers that specifies the order in which frame tiles are shown. A valid animTexFrames string consists of space separated frame numbers and frame ranges. A frame number is single positive integer whereas a frame range is two frame numbers separated by a single dash and no spaces. For example: "0-16 20 19 18 17 31-21". When parsed, the frame ranges will be replaced with the two frame numbers and all frames in between. Frame numbers that exceed the number of cells determined by animTexTiling will wrap around to the beginning. The string field animTexFrames is limited to 255 characters.

Image:Anim_part.jpg

framesPerSec = 16;
animateTexture = true;
animTexTiling = "4 4";
animTexFrames = "0-15";

ParticleEmitter Blend Factors

Because we are limited to a single render batch per particle emitter, we can only use a single blend setting per emitter. For more flexibility, we allow for the specification of any allowable blend function using separate source and destination blend factors. For instance, this allows blend functions like ONE:INVSRCALPHA which, when used with pre-multiplied alpha textures, allows for emitters that mix normal and additive style blends. Source and destination blend factors are defined by the fields srcBlendFactor and dstBlendFactor.

Legal values for srcBlendFactor include: "ZERO", "ONE", "DST_COLOR", "ONE_MINUS_DST_COLOR", "SRC_ALPHA", "ONE_MINUS_SRC_ALPHA", "DST_ALPHA","ONE_MINUS_DST_ALPHA", and "SRC_ALPHA_SATURATE".

Legal values for dstBlendFactor include: "ZERO", "ONE", "SRC_COLOR", "ONE_MINUS_SRC_COLOR", "SRC_ALPHA", "ONE_MINUS_SRC_ALPHA", "DST_ALPHA", and"ONE_MINUS_DST_ALPHA".

For convenience, the blendStyle field can be used to specify a common blend factor preset, such as: "NORMAL", "ADDITIVE", "SUBTRACTIVE", or "PREMULTALPHA". A value of "USER" indicates that the blend function is specified using srcBlendFactor and dstBlendFactor.

ParticleEmitter Drawing Order

The TGEA 1.0 particle system did not maintain frame-to-frame particle ordering which caused visible snapping and blinking in certain particle emitters. In TGEA 1.01, the default particle emitter maintains a consistent youngest-to-oldest drawing order, which is the same as the fixed ordering of TGE particles. Oldest particles are drawn last and will appear to be in front of newer particles when an order-dependent blend style is used.

The new reverseOrder field for ParticleEmitter allows you to reverse the drawing order of particles which is useful in some circumstances. For instance, the particles of an emitter used for chimney smoke will almost always be seen from below. In this case, it may look better to use an oldest-to-youngest drawing order so that the newest smoke particles appear in front of older particles. You get this ordering by setting reverseOrder to true.

For some blend styles, particle ordering is irrelevant and even in cases where the ordering does matter, many particle emitters still look acceptable when rendered with unsorted particles. For this reason, and because particle sorting gets computationally expensive as the density of the emitter increases, particles are rendered without distance sorting by default. Still, some emitter designs with order-dependent blend settings won't look right unless the particles are distance sorted. For these cases, particle distance sorting is enabled using the sortParticles field. When sortParticles is true, the particles will be sorted by distance and drawn in farthest-to-nearest ordering. The nearest particles will appear in front of farther ones when an order-dependent blend setting is used.

Although it is difficult to imagine a case where it would be needed, sortParticles and reverseOrder can both be enabled to get a nearest-to-farthest ordering.

Other Issues

ParticleEmitter contains a field called overrideAdvance which enables or disables an error-correction feature that is not well understood. In TGE, overrideAdvance defaults to false, meaning that the error-correction is normally performed. In TGEA 1.0, the "advance" error-correction operation was completely removed. In TGEA 1.01, the error-correction operation is restored but overrideAdvance now defaults to true. This means you need to recognize when you need to set it to false.

How to recognize when overrideAdvance should be false is a bit difficult to describe. It matters most for particle emitters that emit more than one particle per frame (as determined by ejectionPeriodMS), and don't contain a lot of random variation. If you observe groups of adjacent particles stacking together at the same position or discrete particle color banding that should be interpolated smoothly, you may benefit from setting overrideAdvance to false. Try it and observe what happens.

In TGE, particle textures are specified using the Particle field textureName (or animTexName). These fields still work, but since you can only have one texture per particle-emitter, the new field textureName has been added to ParticleEmitter. If specified, it overrides any textures specified using the Particle textureName field.

If you don't specify any values for ParticleEmitter fields blendStyle, srcBlendFactor and dstBlendFactor, then the setting for Particle field useInvAlpha will choose between an additive blend (when false) and a normal lerpAlpha blend (when true.) Therefore, legacy particles using useInvAlpha will still work as long as mixed useInvAlpha settings are not used in a single emitter.