0xd1ee8634
Flag = false Reverses which winding counts as the front face, so back-face culling removes the opposite side. Stock material only. The property's name is not yet known.
The definition of one emitter of a particle system: when and how many particles it spawns, where they are born, how they move and how they are drawn.
The system list an emitter sits in decides how it runs. An emitter in
complexEmitterDefinitionData runs the full particle simulation and reads every
live property on this page. An emitter in simpleEmitterDefinitionData runs a
lightweight path: it takes size, rotation, quad plane and UV scroll from its
LegacySimple block, moves particles in a straight line, and is known to read only
these properties of this class:
disabled, importance, Filtering, rate, flexRate,
lifetime, period, timeActiveDuringPeriod, timeBeforeFirstEmission,
isSingleParticle, doesLifetimeScale, doesParticleLifetimeScale,
particleLifetime, flexParticleLifetime, particleLinger, emitterLinger.EmitterPosition, SpawnShape, FlexShapeDefinition,
birthVelocity, flexBirthVelocity, flexScaleBirthScale,
isLocalOrientation, particleIsLocalOrientation, isFollowingTerrain,
isRotationEnabled, fieldCollectionDefinition.primitive, texture, particleColorTexture with the
ColorLookUp* properties, modulationFactor, numFrames, frameRate,
startFrame, isRandomStartFrame.blendMode, pass, renderPhaseOverride, isGroundLayer,
alphaRef, miscRenderFlags, colorRenderFlags, meshRenderFlags,
disableBackfaceCull, doesCastShadow, depthBiasFactors, DepthPushPull,
sliceTechniqueRange, softParticleParams, distortionDefinition,
SortEmittersByPos.Audio, materialOverrideDefinitions, LegacySimple.Where a property means something else on a simple emitter, its description says so.
timeBeforeFirstEmission, lifetime, period and
timeActiveDuringPeriod are all measured on it from the system's start. None of
them is measured from the end of another.(system time - timeBeforeFirstEmission) / D, where D is
the smallest of the emitter's end time (lifetime), timeActiveDuringPeriod and
period that is set. With none of them set the phase is always 0. The phase
is neither clamped nor wrapped, so it does not restart each period.0 at birth and 1 at death.Most numeric properties are an embed of constantValue plus optional dynamics.
dynamics the constant is the value. A *VariableData curve supplies the
value alone and constantValue is ignored. A VfxAnimated* curve is multiplied by
constantValue. A curve is a list of times and values, held at its first and
last key; see ValueFloat for the interpolation. times are
positions on the clock the property is sampled on, not seconds.Birth* property, particleLifetime, rate and EmitterPosition are
sampled on the emitter phase. A birth value is sampled once, when the
particle spawns: its curve changes what later particles get and never changes a
live particle.Birth (Color, scale0, velocity, acceleration,
drag, bindWeight, the UV values) are sampled every step on the particle age
fraction.dynamics object can carry a probability table per channel. A table is a
multiplier on the curve's result, looked up with a random number in 0..1 along
its keyTimes. It never replaces or adds.rotation0, worldAcceleration, particleUVScrollRate,
particleUVRotateRate) hold a rate. When the definition loads, the curve is
replaced by its running integral over the particle's life, so the effect at any
age is the accumulated rate. Only a *VariableData curve with two or more keys is
integrated. With a bare constantValue the engine applies one fixed amount for the
whole life, and nothing moves. A constant rate needs a dynamics with two keys of
the same value. See IntegratedValueFloat.When the random number of a probability table is drawn:
| Value | Draw |
|---|---|
The birth vectors (birthVelocity, birthAcceleration, birthDrag, birthScale0, the birth rotation properties, birthOrbitalVelocity) and birthColor |
One independent draw per channel, per particle. |
particleLifetime |
Its own draw per particle. |
birthFrameRate, birthUVOffset, birthUvScrollRate, birthUvRotateRate |
One number shared per particle. isRandomStartFrame and the birth-random colour lookup use the same number, and ParticlesShareRandomValue makes it one number per emitter. |
rate |
Drawn again every step. |
| Values sampled over the particle's life | Drawn again every step, so a table there flickers. |
An effect instance has three flex values, slots 0, 1 and 2. The game
supplies them per instance while the effect lives: as a constant, or bound to the
resource fraction (current over maximum, 0..1) of a unit. A Flex* property names
a slot with mFlexID and combines the slot's current value with a base property.
A slot nobody supplied reads 0, and every flex property is built so that 0
means no change. An mFlexID outside 0..2 also reads 0. Flex values are not
passed on to child effects.
Two kinds exist. A FlexValue* property is additive: it adds
flex * mValue to its base. A FlexTypeFloat property is a multiplier that is
skipped unless it is above zero. No flex property replaces its base.
Four of the additive ones (flexParticleLifetime, flexBirthVelocity,
flexBirthRotationalVelocity0 and the flexBirthTranslation of
FlexShapeDefinition) apply the flex value twice. With plain constants the result
is (base + flex * mValue) * (1 + flex), so it is not linear in the flex value.
An emitter is dropped for good while the system definition is prepared when
disabled is set, when Filtering rejects it by spectator policy, when it is a
simple emitter of a HUD-layer system, or when it can never emit: rate is zero, it
is not isSingleParticle, and it has neither flexRate nor material overrides.
Each time the system spawns, every remaining emitter is tested and instantiated
only if it passes all of: ChanceToNotExist, importance against the
EffectsQuality setting, colorblindVisibility, the keywords of Filtering.
Simple emitters skip ChanceToNotExist and colorblindVisibility.
Every step, an emitter spawns only when all of these hold: system time has reached
timeBeforeFirstEmission, the end time lifetime has not passed, and
system time mod period is below timeActiveDuringPeriod. The count is
(time since the last spawn) * rate, truncated, and at most
rate * 0.33 + 1 particles per step and 1000 per step overall. A step that
spawns nothing keeps accumulating time, so slow rates still emit. Particles
spawned in one step are spread evenly over the step in birth time and along the
system's movement.
Positions, velocities and accelerations live in the emitter's local frame. Each step, for every particle of a complex emitter:
(birthAcceleration + acceleration) * dt.velocity.birthDrag + drag) damps the step velocity.fieldCollectionDefinition) change it, and their change is kept.rotation0.postRotateOrientationAxis, then the
position, then the attachment's current orientation when
particleIsLocalOrientation is set, then the orbit of birthOrbitalVelocity,
then the system's transform, then direction orientation.bindWeight, worldAcceleration and
isFollowingTerrain are applied in world space.A complex particle's colour is the product
Color * birthColor * system colour * modulationFactor, all four channels. For
blendMode Add and Subtract the result is then premultiplied: RGB is multiplied by
alpha and alpha is set to 1. In the shader the colour multiplies the texture
sample and the particleColorTexture sample, and the textureMult sample when
that layer is bound.
Emitters are drawn in render phases, see renderPhaseOverride. Inside one
phase, emitters of all systems are ordered by:
pass, lower first. Among emitters with the same pass, complex emitters draw
before simple ones.blendMode: None, then Add and Subtract, then Alpha,
AlphaAdd, PremultipliedAlpha, Min and Max, then TargetAlpha.SortEmittersByPos.miscRenderFlags byte, lower first.Below that the order is not authored.
Flag = false Reverses which winding counts as the front face, so back-face culling removes the opposite side. Stock material only. The property's name is not yet known.
Replaces the system's two sound names. A system has one create sound and one
persistent sound, from its soundOnCreateDefault and soundPersistentDefault.
When the system spawns, every emitter that is instantiated and has an Audio
block replaces them: a non-empty SoundOnCreate replaces the create sound, a
non-empty SoundPersistent the persistent one. The last one wins, complex
emitters first and then simple ones.
An emitter removed by a spawn gate does not count, so Audio can pick a
different sound per EffectsQuality tier or per ChanceToNotExist roll. It does
not play a sound per emitter or per particle.
F32 = 0 Probability that the emitter is left out of an instance. One random number in
0..1 is drawn per emitter when the system spawns, and the emitter is skipped when
this value is greater. 0 always instantiates it, 1 or more never does.
Colour over the particle's life, RGBA, multiplied with birthColor. See Colour
above for the full product.
Draws the emitter with a material in place of the stock particle shading. When
its Material link resolves, none of the stock render state is built: blendMode,
alphaRef, the stencil and depth bias properties, disableBackfaceCull,
WriteAlphaOnly, DepthPushPull, sliceTechniqueRange and the soft particle,
distortion, erosion, palette and reflection definitions do nothing, and the
material's own passes decide.
Still read from the emitter: the render phase rules, every key of the draw order,
and meshRenderFlags and colorRenderFlags.
Each entry of materialDrivers drives the material parameter of that name, once
per emitter or once per particle depending on the driver.
F32 = 0 Moves every vertex along the line from the camera through it by this many world units before projection. A positive value pushes away from the camera, a negative one pulls toward it. The position on screen does not change; only the depth the particle is tested at does.
Offset of the birth position in the emitter's local frame, sampled on the emitter
phase. It is the base of the birth position: the SpawnShape offset, the
emission mesh point and the emission surface point are added to it.
Normally it is added once, at birth. With IsEmitterSpace it is added again
every step with its current value, so live particles follow a keyed
EmitterPosition.
Optional conditions on the emitter's existence, checked when the system spawns. Unset passes everything.
keywordsExcluded, every entry
of keywordsRequired is among the instance keywords, and, when
keywordsIncluded is not empty, at least one instance keyword is in it.spectatorPolicy. 0 (EnableAlways) always passes. 1
(DisableWhenSpectating) passes only while a client mode flag is off, any other
value (2 is EnableWhenSpectating) only while it is on. That the flag is
spectator mode rests on these names and is not verified.censorPolicy. No code that reads it was found.Multiplies the final scale of every particle by the flex value itself, every
step, when the value is above zero. Only mFlexID is used; mValue is not read.
It scales particle size, not positions.
Scales spawn placement and particle size by the size of the object the effect is bound to, and carries two flex values. The bound object supplies three numbers: its size, a radius and a height.
| Field | Effect |
|---|---|
ScaleBirthTranslationByBoundObjectSize |
Multiplies the birth position (EmitterPosition) by size * value, when that is above zero. Complex emitters only. |
scaleBirthScaleByBoundObjectSize, ...Radius, ...Height |
Weights of a scale multiplier size * a + radius * b + height * c on every particle. A sum of zero or less means 1. |
scaleEmitOffsetByBoundObjectSize, ...Radius, ...Height |
The same weighted sum, multiplying the SpawnShape offset when above zero. |
flexScaleEmitOffset |
Multiplies the SpawnShape offset by flex * mValue, when above zero. |
flexBirthTranslation |
Adds flex * mValue to the birth position, with the double application described under Flex values above. |
The scale multiplier is applied every step and follows the bound object's size while the particle lives, despite the "birth" in the field names. With no bound object all three numbers are zero and the bound-object fields do nothing.
Flag = false Removes the guaranteed first particle. Normally, when the first emission computes to zero particles, one is spawned anyway. With this flag it is not.
Flag = false Changes how EmitterPosition is applied: the particle is born at the origin of
the emitter's local frame and the current EmitterPosition is added every
step. The speed at which EmitterPosition moves is added to the particle's world
velocity. It makes a difference only when EmitterPosition is keyed.
The parameter block of a simple emitter, read only by emitters in the system's
simpleEmitterDefinitionData list. Unset means a block of defaults. It is the
list, not this pointer, that makes an emitter simple.
| Field | Effect |
|---|---|
birthScale, scale |
Uniform scale at birth and over life. |
birthRotation, birthRotationalVelocity |
In-plane angle in degrees and its rate in degrees per second. |
rotation |
Overwrites the angle every step when isRotationEnabled is set. |
orientation |
Plane of the quad: 0 camera facing, 1, 2 and 3 facing world X, Y and Z. 2 lies flat on the ground. |
scaleBias |
Multiplies the quad's two half extents. |
scaleUpFromOrigin |
On a quad that is not camera facing, pins the lower edge and grows upward. |
uvScrollRate |
UV scroll in UV units per second of each particle's age, wrapped. |
hasFixedOrbit, fixedOrbitType |
Replaces straight-line motion by circling the emitter at a fixed radius; the type picks the axis (0, 1, 2 for +X, +Y, +Z and 3, 4, 5 for the negative ones). |
particleBind |
A ramp over the particle's age that controls how much the particle's height follows the terrain, with isFollowingTerrain. |
lockedToEmitter |
Turns particleBind off. |
Optional replacements for over-life properties while the particles linger,
that is from the moment the linger rule of particleLingerType starts. Each
replacement has its own switch in the definition:
| Property | Switch | Replaces |
|---|---|---|
LingerRotation |
UseLingerRotation |
rotation0 |
LingerScale |
UseLingerScale |
scale0 |
KeyedLingerAcceleration |
UseKeyedLingerAcceleration |
acceleration |
KeyedLingerDrag |
UseKeyedLingerDrag |
drag |
KeyedLingerVelocity |
UseKeyedLingerVelocity |
velocity |
SeparateLingerColor |
UseSeparateLingerColor |
Color |
The scale and colour replacements are sampled on linger progress: time since the
linger started divided by particleLinger.
Removed from this class. The link now lives in the CustomMaterial object.
Option<F32> = null Upper limit of the rate produced by rateByVelocityFunction, in particles per second. Unset means 300.
Flag = false Every particle of the emitter uses one stored random number where it would draw
its own shared number at birth: for the probability tables of birthFrameRate
and the birth UV values, for isRandomStartFrame and for the birth-random colour
lookup. The number is drawn again only when the emitter restarts.
Flag = false Tie-break of the draw order between two emitters that both set the flag and
have the same pass and blend rank: the one whose system has the greater
position value draws first. It compares the systems, so emitters of one system
always tie. Which coordinate of the position is compared is not verified.
A spawn shape that gives each new particle an offset from the birth position. A shape can also turn the particle's birth velocity and birth acceleration with the same rotation as the offset. Unset means no offset and no turn.
| Shape | Offset | Rotation of offset, velocity and acceleration |
|---|---|---|
| VfxShapePointDoNotUse | emitOffset |
none |
| VfxShapeLegacy | emitOffset, sampled on the emitter phase |
one turn per entry of emitRotationAngles (degrees) about the matching emitRotationAxes entry, in order |
| VfxShapeBox | x and y uniform within Size as half extents; z on the +Size.z face, or uniform through the depth with flags bit 0x1 |
random quarter turns about Y and Z, or none with flags bit 0x1 |
| VfxShapeCylinder | radius out along X, or uniform in -radius..radius with flags bit 0x1; y uniform in 0..height |
a full random turn about Y |
| VfxShapeSphere | radius out along X, or uniform in 0..radius with flags bit 0x1 |
full random turns about Y, then Z |
flags bit 0x1 fills the volume; without it only the boundary is sampled. The
offset is multiplied by the system scale and by the offset factors of
FlexShapeDefinition.
Hash = "0x0" A name hash that replaces stencilRef when it is not zero. Every distinct
hash drawn in a frame is given a reference value automatically, counting down
from 63, and every emitter or material pass that uses the same hash gets the same
value, across systems. This lets effects share a stencil mask without agreeing on
a number.
Flag = false Mirrors the base layer's U as the last step of the UV transform. A flipped axis also scrolls the other way.
Flag = false Mirrors the base layer's V as the last step of the UV transform.
Flag = false The emitter writes only the alpha channel of the render target. Blending and depth are unchanged. Simple emitters ignore it.
Acceleration over the particle's life, in world units per second squared, in the
emitter's local frame. Added to birthAcceleration and accumulated into the
stored velocity every step.
Alpha erosion: the emitter's alpha is multiplied by a band function of an erosion map against a per-particle drive value that changes over the particle's life, so particles dissolve along the map. Only alpha is affected.
U8 = 5 Alpha test threshold. A pixel is discarded when its final alpha, texture times
colour after erosion, is below alphaRef / 255. 0 turns the test off.
How strongly a live particle follows the system's movement, sampled on the
particle age fraction. Each step the particle is moved by weight times the
distance the system moved in that step, and the offset accumulates. 1 rides
along with the bound object, 0 stays where it was born. Only translation
follows, never rotation.
Constant acceleration fixed per particle at birth, in world units per second
squared, in the emitter's local frame. Added to acceleration every step.
Colour multiplier fixed per particle at birth, RGBA. It is multiplied into
Color every step, see Colour above. Each channel with a probability table draws
its own random number.
Drag per axis fixed at birth, in units of 1 per second. It is added to drag.
Each step every axis of the step velocity loses drag * velocity * dt. Drag can
stop an axis but never reverses it.
Analytic drag. In a system with the UseCalculusForPhysics flag (0x100 of
flags), a particle with
drag is not integrated. Its velocity is not stored and it follows the closed form
offset(t) = (birthVelocity / birthDrag) * (1 - e^(-birthDrag * t)) per axis, so
it eases to a fixed end offset whatever the frame rate. An axis without
birthDrag gets no motion from birthVelocity, and drag is not part of the
formula.
Per-particle multiplier on frameRate, sampled once at birth.
Angular rate, in radians per second per axis, at which the particle revolves
around the origin of the emitter's local frame. Each step the particle's whole
matrix is turned by rate * age, so the particle orbits and its orientation
turns with it. A particle sitting on the origin only spins.
Starting orientation as Euler angles in degrees. All particle rotations are composed as a turn about Z, then X, then Y. Which components a primitive uses is listed on VfxLegacyPrimitiveBase: camera-facing quads read only the X component, as a roll.
Spin acceleration fixed at birth, in degrees per second squared per axis. It contributes 0.5 * age * age * value to the particle's angle.
Spin rate fixed at birth, in degrees per second per axis. It contributes
age * rate to the particle's angle for its whole life.
Scale fixed per particle at birth. It is multiplied into scale0 every step.
What each component does on each primitive is listed on
VfxLegacyPrimitiveBase.
UV translation fixed per particle at birth, in UV units: 1 is one whole texture,
or one flipbook cell on quads. It is the starting value of the scroll and is
inside the wrap or clamp of uvScrollClamp.
UV spin speed fixed per particle at birth, in degrees per second. It contributes age * rate.
UV scroll speed fixed per particle at birth, in UV units per second. The offset is
age * rate, so each particle scrolls from its own birth.
Velocity the particle starts with, in world units per second, in the emitter's local frame. It is stored on the particle and integrated: acceleration, drag and force fields change it over time.
U8 = 0 How the emitter is blended with what is already drawn.
| Value | Mode | Result |
|---|---|---|
0 |
Add | dest + colour * alpha |
1 |
Alpha | colour * alpha + dest * (1 - alpha) |
2 |
Subtract | dest * (1 - colour * alpha) |
3 |
None | The colour replaces the destination. The only mode that writes depth. |
4 |
AlphaAdd | colour * alpha + dest |
5 |
PremultipliedAlpha | colour + dest * (1 - alpha) |
6 |
Min | min(colour, dest) |
7 |
Max | max(colour, dest) |
8 |
TargetAlpha | colour * (1 - dest alpha) + dest * dest alpha |
For Add and Subtract the multiply by alpha is done on the particle colour before it
reaches the shader, and the colour's alpha is then 1, see Colour above.
Vec4 = [1, 1, 1, 1] Purpose not established: no code that reads the value was found.
Gives every particle of the emitter a nested particle system of its own.
childEmitOnDeath it is created when the particle dies instead. The two are
mutually exclusive.childrenIdentifiers by
childrenProbability used as an index. With boneToSpawnAt, every child
spawns, each on the bone at the same position in the list.Vec2 = [0, 0] Added to the two colour lookup coordinates after the scale. Ignored on an axis whose type is 0.
Vec2 = [1, 1] Multipliers of the two colour lookup drivers. On an axis whose type is 0 the scale is the coordinate itself.
U8 = 1 What drives the U coordinate of the particleColorTexture sample, with s and
o the matching components of colorLookUpScales and colorLookUpOffsets.
| Value | Name | Coordinate |
|---|---|---|
0 |
Constant | s. The offset is not added. |
1 |
Lifetime | s * age fraction + o |
2 |
Velocity | s * speed + o, with speed in world units per second, not normalised |
3 |
BirthRandom | s * r + o, with r the particle's shared birth random number |
4 and above |
the same as 0 |
With the defaults of both axes the sample point is (age fraction, 1).
U8 = 0 What drives the V coordinate of the particleColorTexture sample. Same values as colorLookUpTypeX.
U8 = 0 Bit 0x1, ApplyTeamColorCorrection, applies the colourblind recolour to
the emitter's output: with the
colourblind palette active, pixels that are more green than red are shifted
toward blue, pixels that are more red than green toward orange, and both gain
alpha. It has no effect with the normal palette.
The other bits have no reader.
U8 = 0 Filters the emitter by colour palette when the system spawns.
| Value | Emitter is instantiated |
|---|---|
0 |
always |
1 |
only with the normal palette |
2 |
only with the colourblind palette |
3 and above |
never |
Vec2 = [0, 0] Depth bias of the emitter: x is the slope-scaled bias, y the constant bias.
(0, 0) turns the bias off. Which sign moves the emitter toward the camera is
not established.
F32 = 1 Lower bound of the stretch factor of directionVelocityScale. At 0 a particle that stops collapses on the stretched axis.
F32 = 0 Stretches quad particles with their speed. When not zero, one quad axis is
multiplied by max(directionVelocityMinScale, speed * directionVelocityScale),
with speed in world units per second. Camera-facing quads stretch their
scale0.y axis, arbitrary quads their scale0.x axis.
Bool = false Draws both sides of the geometry. Without it, mesh primitives cull their back faces. Quads, beams and trails are always two sided, and a planar projection always culls whatever this flag says.
Bool = false A disabled emitter is dropped while the system definition is prepared and never exists in any instance.
Makes the emitter distort the scene behind it. The emitter samples a copy of
the scene at an offset taken from normalMapTexture, scaled by distortion, and
draws that tinted by its texture and colour.
distortionMode is a bit mask: 1 draws in the late distortion phase, 2 in
the early one, 3 in both, and 0 turns the definition off. With a non-zero
mode the emitter draws only in the distortion phases, not as a normal emitter
as well, and it casts no shadow.
Flag = false Also draws the emitter in the shadow phase, into the shadow map with depth write on and blending off. It applies to an emitter whose phase is chosen automatically, not to HUD-layer, ground layer or distortion emitters.
Flag = false Multiplies the emitter's end time (lifetime) by a scale factor of the effect
instance, once, when the emitter is created. The game supplies the factor when it
creates the effect, and it is 1 otherwise. What the game bases it on is not
established.
Flag = false Multiplies each particle's lifetime at birth by the same instance scale factor as doesLifetimeScale.
Drag per axis over the particle's life, in units of 1 per second, added to
birthDrag. See birthDrag for how drag is applied.
String = "" Path of a static mesh whose surface particles are born on. Each new particle gets
a random point of the mesh, picked by triangle area, added to its birth position
and multiplied by emissionMeshScale. An empty string, a mesh that fails to load
or a mesh without area turns the feature off.
F32 = 1 Uniform multiplier on the point sampled from the emission mesh.
An emission surface: each particle gets an extra
birth offset from a random point on a skinned mesh, on a skeleton's bones or on a mesh
the game links to the effect, and can be sent off along the surface normal. It is
applied after emissionMeshName, on top of it and not instead of it.
Option<F32> = 0 A system age, in seconds. While the system is being stopped, the emitter keeps spawning until the system's age exceeds this value, then counts as finished. The age is counted from the system's start and not from the stop, so an emitter of a system already older than this value finishes at once.
Capped at lifetime + 10 on a complex emitter that has a lifetime, and at 10
on a simple one.
String = "" The emitter's name. Its hash is the key under which the system's
DynamicParameterData addresses this
emitter. No other use by the client was found.
Vec2 = [0, 0] UV scroll speed of the whole emitter, in UV units per second. The offset is
system time * rate, the same for every particle, so all particles scroll in
step. It is added after the wrap or clamp of uvScrollClamp and after the flips,
and it also moves the textureMult layer.
String = "ASSETS/Shared/Particles/DefaultFalloff.png" Loaded and bound to a sampler that no shipped particle shader reads. No visible effect was found.
Force fields acting on the emitter's particles. Field values are sampled on the emitter phase, one value for all particles. Each step they change the particle's velocity in this order, and the change is kept:
| List | Effect on velocity |
|---|---|
fieldAccelerationDefinitions |
Adds acceleration * dt. No position or radius. |
fieldAttractionDefinitions |
Inside radius, adds acceleration * dt toward the field's position, at constant strength. |
fieldNoiseDefinitions |
Inside radius, adds a random kick of velocityDelta * axisFraction, frequency times per second. |
fieldDragDefinitions |
Inside radius, each axis loses speed * strength * dt, down to zero. |
fieldOrbitalDefinitions |
Turns the part of the velocity that is perpendicular to direction into a circle around that axis. Speed is unchanged. |
A field's position is relative to the system and is never rotated. No scale reaches a radius.
Adds flex * mValue to birthRotationalVelocity0 at particle birth, with the double application described under Flex values above.
Adds flex * mValue to the particle's UV offset. mValue is fixed at birth, but
the flex value is read every step, so the UVs of live particles move when the
flex value changes. The term is added after the wrap or clamp of uvScrollClamp.
Adds flex * mValue to birthUvScrollRate at particle birth.
Adds flex * mValue to birthVelocity, per axis, at particle birth. See Flex
values above for where the flex value comes from and for the double application
of this property.
Removed from current builds.
Adds flex * mValue seconds to particleLifetime at particle birth, with the double application described under Flex values above.
Adds flex * mValue to rate, every step. Not applied when
rateByVelocityFunction is in use.
Multiplies the particle's birth scale by flex * mValue, when that product is
above zero. With no flex value, or a product of zero or less, nothing happens, so
it cannot shrink a particle to nothing.
F32 = 0 Flipbook speed in frames per second. Each particle's own rate is
frameRate * birthFrameRate, fixed at birth, and its frame advances with its
age. There is no blending between frames. Zero or a negative rate means no
animation.
Flag = false Applies a fixed rotation, postRotateOrientationAxis, after the particle's own
spin. It turns the orientation of meshes, arbitrary quads and rays.
Camera-facing quads ignore it.
U8 = 2 Quality tier of the emitter, compared with the EffectsQuality setting. It has
two effects.
Existence, decided once when the system spawns:
| EffectsQuality | Importance values not instantiated |
|---|---|
| Very Low, Low | 0, 1, 5 |
| Medium | 0, 1 |
| High | 0, 4 |
| Very High | 4 |
So 0 exists only on Very High, 1 on High and above, 2 and 3 always, 4
only on Medium and below, and 5 on Medium and above.
Emission rate multiplier, applied every step:
| EffectsQuality | 0 |
1 |
2 |
3, 4, 5 |
|---|---|---|---|---|
| Very Low | 0.05 | 0.10 | 0.20 | 1 |
| Low | 0.10 | 0.20 | 0.40 | 1 |
| Medium | 0.20 | 0.40 | 0.60 | 1 |
| High | 0.50 | 1 | 1 | 1 |
| Very High | 1 | 1 | 1 | 1 |
0 and 1 are not instantiated wherever their factor is below 1, so 2 is the
only value whose rate is really reduced. 3 is never removed and never scaled.
Flag = false Orients particles along their movement. The result depends on the primitive:
scale0.y axis
is turned to the particle's velocity projected on the screen. The particle's
own roll is ignored.Flag = false Keeps the particle's height relative to the ground. The ground height under the spawn point is stored at birth, and every step the particle's world Y is shifted by the difference between the ground height under its current position and that stored height. The particle is not flattened onto the terrain.
Flag = false Draws the emitter in the ground layer render phase and in no other: not the
normal or post-distortion phases, not the shadow phase (doesCastShadow is
ignored) and not the distortion phases. It has no effect on simulation.
Flag = true The spawn frame of each particle takes the orientation of what the system is attached to, as it is when the particle is born. Without the flag the spawn frame is axis aligned and only the system's position is used.
A particle keeps the orientation captured at its birth. To make live particles
turn with the attachment, set particleIsLocalOrientation.
Flag = false Offsets each particle's place in the frame loop by numFrames times its shared
birth random number. The offset is continuous, so particles are also out of step
within a frame. Without animation it picks a random fixed frame of the loop.
Flag = false On a complex emitter it enables only rotation0 (and the LingerRotation of
Linger). The three birth rotation properties work without it.
On a simple emitter it makes the rotation of LegacySimple overwrite the
particle's angle every step.
Flag = false The emitter emits once: a single burst of rate particles (truncated, at
least one) at its first emission, and never again, including in later periods.
Restarting the system makes it emit once more.
Bool = false Switches the filtering mode of the emitter's texture samplers; by its name, to point sampling. The palette and alpha erosion samplers are not affected. The mapping to the final filter is not verified.
Flag = false The X scale is used for every axis: for both axes of a quad and all three of a mesh. Rays, trails and beams do not read the flag.
Option<F32> = null End time of emission, in seconds of system time. It is measured from the
start of the system, not from timeBeforeFirstEmission: with a delay of 1 and a
lifetime of 3 the emitter emits for 2 seconds. Unset means the emitter has no
end.
Removed from this class. The map now lives in the CustomMaterial object.
Material overrides for the object the system is attached to. They do not
change the emitter's own particles. Each entry becomes an override that is applied
to the attached object while the system runs, in the same way as the system's
own materialOverrideDefinitions.
Only the entries of emitters that were instantiated take part.
U8 = 1 Bit 0x1, ForceAnimatedMeshZWrite, forces depth write when the emitter
draws a skinned mesh: an
attached mesh primitive, or a mesh primitive that resolved to a skinned mesh.
Static meshes and quads are not affected. The other bits have no reader.
U8 = 0 Bit flags.
| Bit | Name | Effect |
|---|---|---|
0x1 |
DisableZBuffer | Depth test off. Geometry in front of the emitter does not hide it, and it writes no depth. |
0x2 |
Projected | The emitter is never batched with another. |
0x4 |
DisableFow | No fog of war darkening. |
The other bits have no reader. The whole byte is also the last key of the draw order, so any bit changes the order among emitters that tie on the other keys.
Vec4 = [1, 1, 1, 1] A constant RGBA multiplier on every particle of the emitter, applied after
Color and birthColor and before the premultiply of blendMode Add and Subtract.
With those blend modes its alpha therefore scales the colour.
U16 = 1 Length of the frame loop: the animation runs over numFrames frames starting at
startFrame and wraps. It is also the range of isRandomStartFrame. It is not
checked against texDiv. At 0 and at 1 only startFrame shows.
U8 = 0 Bit mask that makes offsetLifetimeScaling use the absolute value of the offset
on an axis.
| Bit | Name | Axis |
|---|---|---|
0x1 |
XSymmetry | X |
0x2 |
YSymmetry | Y |
0x4 |
ZSymmetry | Z |
Vec3 = [0, 0, 0] Changes a particle's lifetime by where it was born in the SpawnShape. The
lifetime becomes lifetime + offset.x * s.x + offset.y * s.y + offset.z * s.z,
never below zero, so the value is in seconds per world unit and it adds. The
offset is the raw shape sample, before the shape's rotation and before any
scaling, and without EmitterPosition.
Palette recolour: the base texel's RGB is replaced by a lookup into
paletteTexture, and its alpha is kept. It is active when the palette texture
loads and paletteCount is above zero.
String = "ASSETS/Shared/Particles/DefaultColorOverlifetime.png" A texture multiplied into the base texel, all four channels. It is sampled at a
per-particle coordinate chosen by colorLookUpTypeX and colorLookUpTypeY,
always with clamp addressing. An empty string binds a white texture.
The sample is dropped in two cases: when the emitter has an
alphaErosionDefinition, and on mesh primitives when a textureMult texture is
bound. On quads, trails, rays and beams with a textureMult texture it is
sampled at the mult layer's UV instead of the lookup coordinate.
Flag = false Every step, the particle's matrix is multiplied by the attachment's current
orientation, so live particles turn with the attachment, positions included. The
spawn frame captured at birth then contributes only its translation, which drops
rotationOverride, scaleOverride and the birth-time orientation.
How long each particle lives, in seconds, sampled on the emitter phase when the
particle spawns and multiplied by its own probability draw. The birth lifetime is
then adjusted by flexParticleLifetime, doesParticleLifetimeScale and
offsetLifetimeScaling. A negative result means the particle never expires.
Option<F32> = 0 Seconds, used only once the emitter is finished: its end time has passed, or
the system is being stopped and emitterLinger has passed. How it is applied to
the particles still alive depends on particleLingerType. It is also the time
span the Linger replacements are sampled over.
The value is capped at particleLifetime + 10 on a complex emitter and at 10 on
a simple one. Unset takes the cap.
U8 = 0 How particleLinger (L) is applied to the particles still alive when the
emitter finishes.
| Value | Name | Starts when | Effect on each live particle |
|---|---|---|---|
0 |
MaxLifetimeAfterEmitterDies | the system is stopping and the emitter is finished | Every step its lifetime is cut to at most L, counted from its birth. |
1 |
FixedLifetimeAfterEmitterDies | the system is stopping and the emitter is finished | Once: its lifetime becomes its current age plus L. |
2 |
FixedLifetimeAfterEmitterStops | the emitter is finished, stopping or not | The same rewrite as 1. |
3 and above |
No change. |
UV spin speed over the particle's life, in degrees per second, as an integrated value.
UV scroll speed over the particle's life, in UV units per second, as an
integrated value. It is added after the wrap or clamp of uvScrollClamp, so it is
never clamped.
I16 = 0 Draw order among emitters, lower first. It is the first key of the order inside a render phase and it works across systems and emitter lists, see Draw order above.
For an emitter whose phase is chosen automatically, the sign also picks the phase:
a negative pass draws in the Default phase, before DistortionAll, and 0 or
more draws in PostDistortion, after it.
Option<F32> = null Length of the emission cycle, in seconds. The emitter may spawn only while
system time mod period is below timeActiveDuringPeriod. The cycle is aligned
to the system's start, not to timeBeforeFirstEmission. Unset means one cycle
that never repeats.
Vec3 = [0, 0, 0] The fixed rotation used by hasPostRotateOrientation. Despite the name it is not
an axis: the three components are Euler angles in degrees about X, Y and Z.
Pointer<VfxPrimitiveBase> Pointer<VfxLegacyPrimitiveBase> The object that turns each particle into geometry, see VfxLegacyPrimitiveBase. Unset means a camera-facing quad.
| Primitive | Draws | Simple emitters |
|---|---|---|
| VfxPrimitiveCameraQuad | a camera-facing quad | drawn |
| VfxPrimitiveCameraUnitQuad | a camera-facing quad of half the size | nothing |
| VfxPrimitiveArbitraryQuad | a quad on the particle's own X and Y axes | drawn |
| VfxPrimitiveRay | a quad along the particle's +Z | nothing |
| VfxPrimitiveMesh | one mesh per particle | drawn |
| VfxPrimitiveAttachedMesh | the bound character's own skinned mesh, per particle | drawn |
| VfxPrimitiveCameraTrail | a camera-facing ribbon through the particles in birth order | nothing |
| VfxPrimitiveArbitraryTrail | the same ribbon, oriented by the particles | nothing |
| VfxPrimitiveBeam | one segment from the system position to the target attachment | nothing |
| VfxPrimitiveCameraSegmentBeam | a segmented beam | nothing |
| VfxPrimitivePlanarProjection | a projection onto the ground | drawn |
| VfxPrimitiveNonRenderable | nothing; the particles still simulate | nothing |
A simple emitter with a primitive it cannot draw still simulates its particles.
Emission rate in particles per second, sampled on the emitter phase. The rate used for a step is built in this order:
rateByVelocityFunction, when it is non-zero, replaces rate and steps 2
and 3.rate.flexRate is added.importance rate multiplier for the current EffectsQuality.The first time the emitter emits, a count of zero is raised to one particle
unless HasVariableStartTime is set.
A pair (x, y) that, when not (0, 0), replaces the emission rate with
speed * x + y, where speed is how fast the whole system instance moved in the
last step, in world units per second. rate and flexRate are not read in that
case. The emission-surface factor, the importance multiplier and the per-step
cap still apply.
Fresnel and reflection terms for mesh emitters.
fresnelColor
added toward grazing angles.reflectionMapTexture, added to the colour with an
opacity between reflectionOpacityDirect and reflectionOpacityGlancing. It
needs the map to load, a uvMode of 0, 3, 4 or 5, and a quality
setting above the lowest.U8 = 7 Forces the emitter into one render phase. 7 means not set, and the phase is
then chosen automatically.
| Value | Phase | Drawn |
|---|---|---|
0 |
Default | third |
1 |
Shadow | into the shadow map, only when shadows are on |
2 |
DistortionNoCharacter | first |
3 |
DistortionAll | fourth |
4 |
PostDistortion | fifth |
5 |
GroundLayer | second |
6 |
HudLayer | last |
Automatic choice, when the value is 7:
HudLayer.isGroundLayer puts it in GroundLayer only.distortionDefinition puts it in the distortion phases only.pass decides: negative draws in Default, zero or more
in PostDistortion.doesCastShadow adds Shadow.A forced value drops all of those rules, and a value above 7 matches no phase,
so the emitter is never drawn. An emitter with a
VfxPrimitiveNonRenderable is in no phase.
Spin rate over the particle's life, per axis, as an integrated value. The
rate is in degrees per 1/60 second, so 1 turns 60 degrees per second. The
accumulated angle is added to the birth rotation terms. It needs
isRotationEnabled and a particle with a finite lifetime.
Vec3 = [0, 0, 0] Rotation of the emitter frame (see translationOverride), as Euler angles in
degrees. It turns everything in the emitter's local frame: birth positions,
velocities, accelerations and the particles' own orientation.
Scale over the particle's life. The final scale is
scale0 * birthScale0 * the scale factors of FlexShapeDefinition * FlexInstanceScale,
and the system scale multiplies it when the particle is drawn.
What each component does on each primitive is listed on VfxLegacyPrimitiveBase.
Vec3 = [1, 1, 1] Per-axis scale of the emitter frame (see translationOverride). It scales birth
offsets and travelled distance, and it scales mesh and arbitrary quad particles
because their matrix carries it. Camera-facing quads take only their position
from the matrix, so their size does not change.
{
"emitRotationAngles": [],
"emitRotationAxes": [],
"emitOffset": { "constantValue": [0, 0, 0], "dynamics": null },
"birthTranslation": { "constantValue": [0, 0, 0], "dynamics": null }
}Removed from current builds. SpawnShape and EmitterPosition were added when it was removed.
F32 = 0 Above zero, the emitter uses the slice shaders. The red channel of texture
is treated as a position map, and the alpha of the particleColorTexture sample
picks a position on it. A pixel is visible in a band around that position, and
this value is the band's half-width in red-channel units. Colour comes from the
particleColorTexture sample, the particle colour and the texture's green
channel; alpha from the band and the texture's alpha.
Fades the emitter where it comes close to scene geometry. With d the depth
distance between the scene and the particle pixel, the fade is a smooth step in
from beginIn over deltaIn, minus a smooth step out from beginOut over
deltaOut. A beginOut of zero or less means no fade out.
It is active only on Medium EffectsQuality and above, and only on plain quad
and mesh emitters.
U16 = 0 First frame of the loop, and the frame shown when there is no animation.
U8 = 0 How the emitter uses the stencil buffer, with the reference value from
stencilRef or StencilReferenceId.
| Value | Name | Test | Writes |
|---|---|---|---|
0 |
Disabled | off | no |
1 |
WriteMask | always passes | the reference where it draws |
2 |
TestEqual | draws only where the stencil equals the reference | no |
3 |
TestNotEqual | draws only where the stencil differs from the reference | no |
4 |
WriteMaskIfTestNotEqual | draws only where the stencil differs | the reference where it draws |
An emitter in mode 1 or 4 still draws its colour. Only the low 6 bits are
compared. Complex emitters only, and not in the shadow phase.
U8 = 0 Stencil reference value for stencilMode. Used only when StencilReferenceId is zero. Values that are equal modulo 64 compare as equal.
U8 = 0 Address mode of the base texture, on all axes.
| Value | Mode |
|---|---|
0 |
Wrap |
1 |
Mirror |
2 |
Clamp |
3 |
Border |
| other | Wrap |
It also applies to the distortion normal map. textureMult, the palette and the
erosion map have their own address modes, and particleColorTexture and the
reflection map always clamp.
Vec2 = [1, 1] Columns and rows of the base texture's flipbook grid. The frame number is split into a cell, left to right and then top to bottom, and the primitive's UV is mapped into that cell. On quads the whole UV transform acts inside the cell.
String = "" The base texture. An empty name or a texture that fails to load binds a transparent black texture, so the emitter draws nothing visible in the usual blend modes.
A second texture layer, multiplied into the base texel on all four channels. The
layer has its own UV transform and its own flipbook grid (texDivMult), but it
shares the base layer's frame number. It is active only when its texture loads.
Option<F32> = null Seconds at the start of each period during which the emitter may spawn. Unset
means always. With period unset it limits emission to the first seconds of the
system. Zero or a negative value never spawns.
F32 = 0 Seconds of system time before the emitter may spawn. It is also subtracted from
system time in the emitter phase. It does not move lifetime, period or
timeActiveDuringPeriod, which keep counting from the system's start.
Vec3 = [0, 0, 0] Translation of the emitter frame: an extra frame scale, then rotation, then translation built from the three *Override properties, in which the emitter's
local frame sits. The translation moves the origin every particle is born around.
It follows the attachment's orientation when isLocalOrientation is set and world
axes otherwise.
Flag = true When a point was sampled from the emission mesh, the particle's birth velocity and birth acceleration are pointed along the triangle's normal. Their magnitudes are kept. The particle's own orientation is not changed.
Flag = false Selects the masked shader variant: the vertex shader passes a mask coordinate built from the particle's world X and Z. What the mask texture holds and how the pixel shader uses it is not established.
U8 = 0 How texture coordinates are produced.
| Value | Name | Effect |
|---|---|---|
0 |
Default | UV from the primitive, through the UV transform. |
1 |
ScreenSpace | Both layers are sampled with screen-space coordinates, run through their UV transforms. |
2 |
LockAlpha | Colour is sampled at the transformed UV, alpha at a UV that does not scroll. |
3 |
LocalSpace | The base layer's UV comes from the vertex position in particle space (x and z). Meshes only. |
4 |
LocalSpaceMult | The same for the textureMult layer only. |
5 |
LocalSpaceBoth | The same for both layers. |
On anything but a mesh, 3, 4 and 5 behave as 0.
F32 = 0 Adds a UV offset that depends on where the particle is relative to the camera,
multiplied by this value. Camera-facing quads apply it only with uvMode 0,
mesh primitives only with uvMode 1 and only from the X and Z distance. The
visual result is not established.
Rotation of the UV about uvTransformCenter, in degrees, sampled on the particle age fraction. The two rotate rates add to it.
Scale of the UV about uvTransformCenter, sampled on the particle age fraction.
The UV transform of a complex particle runs in this order:
uvTransformCenter by uvRotation, plus
age * birthUvRotateRate, plus the accumulated particleUVRotateRate.uvTransformCenter by uvScale.birthUVOffset + age * birthUvScrollRate, wrapped or clamped
(uvScrollClamp), then the accumulated particleUVScrollRate and the
flexBirthUVOffset term.TextureFlipU and TextureFlipV.emitterUvScrollRate is added to the translation afterwards.
Flag = false Changes how birthUVOffset + age * birthUvScrollRate is bounded. Off, the sum is
reduced to its fractional part every step, so it wraps. On, it is clamped to
-1..1 per component, so the scroll runs once and stops. The other scroll terms
are never bounded, and the texture's address mode is not changed.
Vec2 = [0.5, 0.5] Pivot of the UV rotation and UV scale, in UV units. It does not affect scrolling or the flips.
Extra velocity over the particle's life, in world units per second, in the emitter's local frame. It is added to the stored velocity for each step's movement and is not stored: when the curve returns to zero its contribution stops at once.
Acceleration in world axes, in world units per second squared. It is an integrated value: the engine integrates the curve twice and adds the resulting displacement to the particle's world position, after every frame of the emitter. Drag and force fields do not affect it.