Skip to content

What mesh particles give and what they cost

A stock ParticleEmitter draws flat pictures. Roblox’s documentation calls it “an object that emits customizable 2D images (particles) into the world”. A Part-Icles particle is a real instance. It is a duplicate of your own Part, MeshPart or Model, and the Part_Icles module moves and reshapes it over its life.

A real instance can do things a flat picture cannot. It also costs more to keep alive. This page gives both sides, and shows how the module keeps the cost down.

The module is readable source. Everything on this page about the module can be checked by opening it.

What it makes possible:

  • An effect built from true 3D shapes, lit by the scene and seen from every side.
  • An informed choice between a mesh particle and a stock ParticleEmitter for each layer of an effect.
  • A heavy effect made cheaper, by knowing where the module can take a shortcut.
A mesh particle canIn practiceDescribed in
Be any shapeThe particle is a duplicate of your Part, MeshPart or Part with a SpecialMesh. It keeps its Material, Decals, Textures and SurfaceAppearance.Part
Change size on each axisSize has a graph each for X, Y and Z. A shockwave ring can widen without growing taller.Part
Carry pictures that change by themselvesEach Decal on the particle has its own Transparency, Color and Brightness graphs, and its own flipbook.Decals and flipbooks
Change shape during its lifeThe particle steps through a list of meshes.Mesh Frames
Be a whole ModelThe Model is duplicated, moved and scaled as one.Model
Carry other effectsEmitters, stock ParticleEmitters, Trails, Beams and Lights inside the RenderTemplate travel with every particle.Nesting
React to the worldOn Hit can remove the particle, stop it or bounce it off a surface.Events
Fire other effectsAn event fires another emitter where the particle was made, hit something or ended.Events
Be scripted one by oneAn event script can move, recolour, resize, freeze, push or remove a single particle.The event script and its payload
Follow a moving objectA particle in flight can follow a Part, an Attachment, a Model, a Bone or the camera.Link
Play in placeIn Animate mode the template itself plays, once or in a loop, with no duplicate made.Emission
Change speedA Timescale graph slows, freezes or speeds up an emitter. A script can do the same for one play.Starting, stopping and waiting

The same Rate, Lifetime and graphs also drive lights, sounds, beams, trails, highlights and screen effects. The Particiliary lists every kind.

The module puts no ceiling of its own on Rate or Lifetime. Its one limit is the Particle Cap.

A stock particle is not an instance. A mesh particle is, and that sets its cost.

CostDetail
One instance for each particleA Model particle is a whole Model. A Rocks burst, a Lightning bolt and a Rope are many parts each.
One update by script, for each live particle, on every frameAll updates run in one script, one after another.
Property writes at each stepPosition and rotation, Size, Transparency and Color are each written when a particle enters a new step.
A further write on every frameOnly for a particle that follows a link, or uses Orientation or Z-Offset.
The emitter’s settings are read at every emitThis is why an edit shows on the very next particle.
No saving for distance or for being off screenA particle behind the camera is updated like any other.

Part-Icles has published no measured comparison with the stock ParticleEmitter. Measuring shows how to compare the two on your own effect.

A particle’s life is divided into steps. Advanced ▸ Anim. Steps sets how many, and it starts at 100. The particle is moved, sized and coloured only on a frame where it enters a new step. On every other frame nothing is written.

A particle that lives 3 seconds at 100 steps is updated about 33 times a second, not 60. Between two steps the particle holds its pose. Nothing is blended in between.

CaseEffect of Anim. Steps
A long lifeFewer steps mean fewer frames with work to do.
A life shorter than the steps allowNo saving. At 60 frames a second a life of 0.5 seconds has 30 frames. 100 steps and 30 steps both do work on all 30.
Drag, Rotation Mode Speed, Dir. Mode Local, or a Model emitterThe motion is worked out once for each step, so the cost also rises with the number of steps.
A Beam emitterNot used. The Blender, and every Beam graph that is not flat, are followed on every frame.
A Trail emitterThe six graph rows are read in steps. The Blender is followed on every frame.

Advanced describes the row.

For most particles the module does not walk through the steps one by one. It takes the distance travelled since the last update from the area under the Speed graph, in one calculation. Acceleration is added the same way. The path is the same at any frame rate.

This holds for Part and Attachment particles with Drag at 0, Rotation Mode OverLife, Reverse Motion off, and a Dir. Mode other than Local.

SettingWhat the module does in its place
Drag above 0Works through each step crossed, slowing the particle as it goes.
Rotation Mode SpeedWorks through each step crossed, adding up speed and turn.
Dir. Mode LocalWorks through each step crossed, and reads the travel direction again from the particle’s new rotation.
A Model emitterAlways works through each step crossed.
Reverse MotionWorks out the whole path once, when the particle is made, and plays it from the end. At most 500 steps.

When a particle is made, each of its number graphs is checked. A graph that is flat, with no random spread, is read once and its value kept. It is not read again for that particle.

EmitterGraphs covered
PartSpeed, Brightness, Transparency, Size, Rotation Speed, Displacement, Strength
AttachmentSpeed, Rotation Speed, Displacement
ModelSpeed, Scale, Rotation Speed, Displacement
BeamEvery graph row. A flat one is written once, when the beam is made, and not touched again.

Three limits apply.

  • The Color graph is read at every step, flat or not.
  • A graph with a random spread is never flat. Each particle has its own offset.
  • The values are still written at each step. The shortcut removes the reading, not the writing.

Turbulence left at 0 is skipped entirely.

With Advanced ▸ Pool off, every particle is built when it is made and destroyed when it ends. With Pool on, a finished particle is hidden and kept, and the next emit takes it back out.

Pool starts off on every type except Rocks. Switch it on for an emitter that streams.

SubjectRule
How long an idle particle is kept5 seconds. Idle particles are cleared in small batches, so one may last a second or two longer.
How many idle particles one emitter keepsAbout six times its Rate, plus 8. At Rate 10 that is 71.
How many are kept in all2048, across every emitter.
A burst larger than the limitThe surplus is destroyed. A burst of 200 at Rate 10 keeps 71 and rebuilds the rest each time.
An edit to the emitterIts idle particles are discarded, so an old look is never reused.
Part_Icles:Deactivate()Every idle particle is destroyed.
Animate mode, Sound emitters, Blur, Bloom, ColorCorrection, AtmosphereNot pooled.

Pool pays off for a steady stream, where a particle is wanted again within 5 seconds. It does little for a rare, large burst.

Transform sets these on the RenderTemplate once. Every particle is a duplicate of the template, so every particle has them.

PropertySet toWhat it means for a particle
AnchoredOnIt is not moved by physics.
CanCollideOffNothing bumps into it.
CanQueryOffRaycasts pass through it.
CanTouchOffIt fires no Touched events.
MasslessOnIt adds no weight to anything.
CastShadowOffIt casts no shadow.
LockedOnIt cannot be clicked in the viewport. Not set on the parts of a Model emitter.

The settings are yours to change. Switch CastShadow on in the RenderTemplate, and every later particle casts a shadow.

On Hit does not need CanQuery. It casts a ray from where the particle was to where it is now, and tests that ray against the world.

Live particles are kept in a folder named EmittedPartsUsingPart_icle. It sits under the camera of the machine that made the particles. On a player’s machine that is the player’s own camera. Neither the folder nor the particles are saved with the place. Emit Into puts an emitter’s particles somewhere else.

Idle frames write nothing, and removal is cheap

Section titled “Idle frames write nothing, and removal is cheap”
  • On a frame where a particle’s step has not changed, the module writes nothing to it.
  • The update of a Part, Attachment or Model particle builds no table.
  • A finished particle is taken off the live list by moving the last entry into its place. The list is never shifted.
  • The first values of every graph are set before the particle is shown. A particle never appears for one frame with the wrong size or colour.
  • An emitter that is switched off, with no particles in flight, costs nothing on each frame.

The module stops making particles when the number alive reaches the cap. The cap starts at 1000. Particles in their Linger time count too.

At the cap a new emit is skipped. It is not held back for later. At most once a second, the Output window reads:

[Part-Icles] active particle cap (N) reached - new emits skipped (user Module code still runs).

In the editor, ≡ ▸ Settings ▸ Particle Cap sets the cap. In the game, a script sets Part_Icles.MAX_ACTIVE_PARTICLES. A Rocks burst, a Lightning bolt, a Rope and a Model each count as one.

Emission and motion do not depend on the frame rate

Section titled “Emission and motion do not depend on the frame rate”

A stream keeps count of time, not of frames. On each frame it emits once for every whole 1 / Rate seconds that have passed, and carries the remainder forward. An emitter at Rate 40 makes 40 particles a second at 30 frames a second and at 144.

Steps are also counted from time. A particle follows the same path, at the same pace, on a slow machine and a fast one.

On a player’s machine the module updates in the render step, after the camera has moved. On a server it updates on Heartbeat.

Nested emitters are not duplicated with their parent

Section titled “Nested emitters are not duplicated with their parent”

A RenderTemplate can hold other emitters. When a particle is made, its duplicate is built without them. Each nested emitter then fires in the ordinary way, with the new particle as the thing it follows. The settings of a nested emitter are never duplicated for each parent particle.

EmitterHow it is kept cheap
RocksThe whole path of every chunk is worked out once, 8 chunks on each frame. After that, each frame makes one grouped move of all the chunks. Nothing is written once every chunk is at rest.
LightningThe shape of a bolt is rolled again at its Jitter Rate, not on every frame. All its segments are placed in one grouped move.
RopeThe rope is advanced in fixed steps of one sixtieth of a second, at most three on a frame. All its segments are placed in one grouped move.
Camera ShakeNo instance is made. Every live shake is added up, and the camera is written once on each frame.
DistortionOne shared plane serves every distortion that is alive.
  • An event script is loaded once and kept. It is loaded again only when its text changes.
  • With no event switched on, a particle pays for one check.
  • On Hit casts one ray for each particle on each frame. The ray is skipped when the particle has moved less than 0.05 studs.
  • On Hit ▸ HitTick spaces the hit tests out. The next ray then covers the whole distance since the last one. A particle that has moved further than half its own diagonal is tested at once.
  • At most 256 events run on one frame. The rest are dropped, and the Output window says so.

With Advanced ▸ Preload Texture on, the module loads the emitter’s textures when it starts, and holds them. The first particle then shows its picture at once. A texture shared by several emitters is held once. Advanced describes the row.

What Roblox says of the stock ParticleEmitter

Section titled “What Roblox says of the stock ParticleEmitter”

Roblox’s page on particle emitters states the costs and the limits of the stock emitter.

Particle size can impact performance due to fill-rate. The more pixels particles occupy on a player’s screen, the more costly it is on the GPU.

Particle count can impact performance due to overdraw, especially when particles are overlapping. The more layers of transparent effects on screen, the more costly it is on the GPU.

A single particle emitter can create up to 400 particles per second (100 per second on mobile).

Particles have a maximum lifetime of 20 seconds.

The effectUse
Hundreds or thousands of small particles alive at once: rain, snow, dust, dense smokeA stock ParticleEmitter. Every mesh particle costs an instance and an update by script.
A flat picture that faces the camera and only changes size, colour and transparencyA stock ParticleEmitter. Nothing a real instance gives is being used.
An ambient effect that runs all the time, often far away or off screenA stock ParticleEmitter. The module makes no saving for distance.
A shape with depth: a shard, a ring, a slash, a rock, a shockwave domeA mesh particle.
A particle that must bounce, stop on a surface or fire something where it landsA mesh particle, with On Hit.
A particle that carries a light, a trail or a second effectA mesh particle, with the passengers in its RenderTemplate.
A particle a script must reachA mesh particle.
A few strong shapes with a cloud of small sprites around themBoth.

The two work together. A stock ParticleEmitter placed in a RenderTemplate fires for every mesh particle. A stock ParticleEmitter in a Folder of emitters fires with the rest. The plugin also edits stock ParticleEmitters as they stand. See Editing stock ParticleEmitters, Trails and Beams.

To getDo this
Fewer particles alive at onceLower Rate, the Emit count, Lifetime or Linger. A stream keeps about Rate times Lifetime alive.
Less building and destroyingSwitch Pool on for an emitter that streams.
Fewer updates on a long-lived particleLower Anim. Steps until stepping shows, then raise it a little.
The one-calculation motionKeep Drag at 0, Rotation Mode at OverLife, and Dir. Mode away from Local, where the look allows.
Graphs read onceLeave a graph flat, with no random spread, where the look allows.
Fewer hit testsRaise On Hit ▸ HitTick. Switch On Hit off where it is not needed.
Less work for each parent particleLower the Emit count of nested emitters. Counts multiply.

The Optimization indicator gives an estimate worked out from the settings of the selected emitters. It is not a measurement. Exercise 20 uses it on a finished effect. Performance lists symptoms and actions.

Roblox’s MicroProfiler shows where each frame’s time goes.

StepControlActionResult
1Studio, with the game runningPress Ctrl+F6, or ⌘F6 on a MacThe MicroProfiler opens.
2Your scriptFire the effect made of mesh particlesThe MicroProfiler shows the frame time during the effect.
3Your scriptFire the same look built with a stock ParticleEmitterThe MicroProfiler shows the frame time during that effect.
4The MicroProfilerCompare the twoEach frame shows which part of the engine took the time.

On a player’s machine the module updates its particles in the render step. Roblox’s tag table lists scripts bound to the render step under fireBindToRenderSteppedCallbacks, and stock particles under updateParticles.

Measure on the hardware your players use.

  • The module does not skip particles that are off screen or far from the camera.
  • The module updates every particle in one script. It does not spread the work over several.
  • Part, Attachment and Model particles are each moved by their own write. Only Rocks, Lightning, Rope and Distortion use a grouped move.
  • The Color graph is read at every step, even when it is flat.
  • Part-Icles publishes no benchmark against the stock ParticleEmitter.