EvenRing

EvenRing

Generator. Emits particles evenly spaced in time, like a ring of emission slots. (Formerly named GenEvenPeriodic.)

The ring-in-time model. Each slot fires once per period, where the period is 100 / rate seconds (the time it takes to fill the emitter’s whole capacity once). A slot is reused every period, so a particle must die before its slot’s turn comes around again. If a particle lives longer than the period, its slot is still occupied when its turn returns, the shot is dropped, and a gap forms that propagates as visible “waves”.

All properties must remain constant over time, otherwise generating glitches may occur. The rate is specified as a percentage of emitter capacity per second.

Setting the rate from particle life. Choose the rate straight from how long your particles live:

rate = 100 / life

For example, 2-second particles → 50%, 3-second particles → 33.3%. A small safety margin is applied automatically by every backend (GPU33 as well as the CPU/JS and C# runtimes), stretching the real ring period just past the particle life (by about 2 %). This means these obvious values fill the capacity smoothly without waves — you do not need to shave the rate down by hand. (This holds as long as one shot fits into the emitter — see Burst below.)

Gaps in the stream. A particle that dies in a frame frees its slot before the generator shoots in that frame (same-frame slot reuse, issue #416), so a slot does not wait an extra frame for its next shot. For a stream without gaps:

  • set the rate to 100 / lifetime (the Emitter Guide's life link does it);
  • keep frames shorter than the particle lifetime (at 30 FPS, particles live longer than 33 ms);
  • keep the rate, delay, start phase and burst fixed numbers;
  • use a whole-number Burst that divides Max. num. particles.

A particle keeps its slot while its attached emitters are still running, so their shots can still be lost. On GPU33 the same-frame reuse needs EvenRing to be the emitter's only generator and the emitter to have no attached emitters of its own. A shot that falls exactly on the boundary of two frames (for example the first shot after a start delay of a whole number of frames) is not lost in emitters that are not attached; attached emitters still compute the frame window from their own clock.

On GPU33 the shader keeps the emitter time in single precision, so an effect that runs without a restart can still lose shots. In the tested cases (lifetimes of 0.2–2 s at 30 or 60 FPS) this was about 0–0.7% during the first hour; tests that start about 5.6 hours into a run measured 1.7–3.6%. These are examples, not upper bounds: the result depends on the lifetime, rate, capacity and frame time. Restarting the effect resets the time.

Getting the fix.

  • JavaScript 1.1: re-export the effect.
  • C# 1.2 and Unity: update the runtime package; re-exporting is not needed for this fix.
  • GPU33: re-export the effect for the shader fixes; the fix adds no new runtime requirement, so the effect's other features still decide which runtime it needs. Update the GPU33 runtime packages for a clock in double precision: the old single-precision clock drifted on long runs (about 5% fast from about 4.5 hours of running at 60 FPS) and stopped after about 4.8 days, which could freeze animation driven by the effect or emitter time and disturb time-based emission. The new clock serves already exported effects too.

On the CPU the particles that were already alive are now updated before EvenRing shoots: in a frame with shots they see the system time from the start of the frame and the generator's Burst size and Shots made from before those shots. Slot reuse and the order of random numbers change too, so an EvenRing effect with a fixed seed may look different.

Shot timing on different backends. When the emitter's Max. num. particles divides evenly by Burst and the Burst is a whole number, every backend fires at the same moments. Otherwise GPU33 fits a whole number of shots into the ring (for example, 60 particles with Burst 7 make 8 shots per ring), while the CPU/JS and C# runtimes keep the exact rate, so the shots are spaced slightly differently. The shot ticks on the timeline follow the renderer selected for the preview.

Properties & inputs:

  • Generating rate (input | property): Percentage of emitter capacity generated per second. Also sets the ring period (100 / rate seconds).
  • Particle max. life (property): Helper to pick the rate by eye. Enter roughly how long your particles live and the rate is set to 100 / life. It is a standalone estimate — it is NOT read from the Termination section (an emitter may have several life limits, or none).
  • Enable time limit (property): Limits the generating duration in seconds, counted from the emitter start including Delay: only shots scheduled at or before the limit fire. A limit earlier than the first shot emits nothing.
  • Enable shots limit (property): Limits the total number of emission events: only the first N shots fire, a fractional limit rounded up (2.5 allows three). A limit of 0 still lets the first shot fire, unless the time limit stops it. On GPU33 the generator honours the time and shots limits, but strips do not take them into account yet when they work out the ribbon's head and tail.
  • Delay (input | property): Delay in seconds before generation starts.
  • Start Phase (input | property): Value from 0 to 1. If 1, the first shot fires immediately. If 0, a full period elapses first.
  • Burst (input | property): Number of particles per shot. Keep it at or below the emitter's Max. num. particles. A larger burst cannot fit into the emitter in one shot: the CPU runtimes emit only as many particles as there are free slots and drop the rest, so Burst Pos. never reaches its end; on GPU33 every free slot of the emitter fires once per ring instead, and for a whole-number Burst the shots follow at the same pace as on the CPU. The editor marks the block with a warning when a fixed Burst is larger than Max. num. particles.
  • Burst pos mode (property): Controls how the Burst Pos. output is spread across the particles of one shot. Normalized (default) runs the first particle to 0 and the last to 1 (index / (burst − 1)). Linear runs the first particle to 0 and the last to 1 − 1/burst (index / burst), so the value never quite reaches 1 — useful when Burst Pos. drives a looping or tiling gradient where the last particle should not land on the same value as the first.

Outputs:

  • Burst Amount (float): Number of particles in the current burst.
  • Burst Pos. (float): Position of a particle within the burst. The range depends on Burst pos mode: Normalized gives [0; 1] (last particle = 1), Linear gives [0; 1 − 1/burst] (last particle < 1).
  • Shots Made (float): How many shots this generator had already completed when the particle was born — 0 for the particles of the very first shot, 1 for the second one, and so on. Useful to make each shot differ from the previous ones (colour, size, direction). In the Emitter Guide the same value is available directly as the Number of shots value type.

On GPU33 the shots count is not stored but derived from the emitter's time, which gives the same numbers as the CPU runtimes as long as the generator's timing inputs (rate, burst, delay, start phase) are constant. If any of them is connected to a changing value, exporting reports a warning, because the count may then drift from the CPU runtimes.