Page contents

weather_particle_system

Weather particle systems define the appearance, density, and physical behaviour of weather like rain and snow.

Usage

To use weather in your level, you must create weather palette entries in Sapien referencing a weather particle system and optionally wind. You then assign these entries to BSP clusters within the level, allowing different areas to have different weather. Areas under overhangs and roofs which should not have weather can be masked with weather polyhedra, added while modeling the level.

Simulation

Each weather particle type get simulated in a cube the size of its fade out end distance, originating at the world's 0,0,0 origin point. It can be visualized by enabling debug_point_physics. Particles wrap around when they reach the edge, making the simulation tileable. All other weather particles in the level are simply a trick of rendering.

Individual particles are simulated according to their point_physics and the effects of wind, with the exception of collision detection. The simulation resets when the weather is hidden then becomes visible again, such as when moving between clusters, and you may see the particles begin to accelerate again under the influence of wind friction or gravity. Because the particles wrap around at the edge of the cube, they will retain any velocity they had and continue to accelerate under gravity. Ensure that your point_physics have sufficient air friction to slow the particles down.

Limits

The game can simulate up to 512 weather particles. There is therefore a tradeoff between particle count and view distance: if your view distance is large, a high density is not possible because the budget of 512 particles must be spread out in an exponentially larger simulation cube. Here's a table summarizing the maximum densities for various fade out end distances:

Fade out distance (wu)Max achievable density (particles/cubic wu)
0.54096
1512
264
48
81

Setting the particle count higher than these values will not achieve a higher density. When a weather particle system has multiple particle types, the first type gets first "dibs" on the particle budget. If it uses up all the budget then the following types' particles will not be present.

If you require a high density of particles, simply include multiple particles spaced out within the sprite texture and set the random rotation flag. The stock snow sprite does this and it's fairly convincing. If you need to increase the particle radius to accomodate this, don't forget to adjust density accordingly.

Particle acceleration

Use the acceleration parameters to give weather particles their own acceleration, independent of any external forces. Particles have an individual acceleration vector which can change direction over time, and the amount of acceleration can vary too. This is used to simulate particles that move on their own like flying insects.

Particles with similar acceleration parameters to c10's beetles. There is no wind in this scenario.

Added motion

The game adds fixed motion to weather particles each rendered frame, unrelated to wind (global or local variation) or acceleration. Added motion is not "true motion" for the purposes of particle orientation, so you may see velocity-oriented particles unaligned with their apparent direction of movement.

The direction is "random" and unique to each particle, unchanging after creation. However, the algorithm the game is using for this introduces some likely unintended bias in the direction. The first 128 particles created have a general +x -y +z direction, similar to the bias in wind local variation. At 256 particles, some particles now move in the -x direction too. At the limit of 512, there is a good distribution of horizontal directions but the particles still move upwards on average. The bias is noticeable at high framerates, but not at 30 FPS. When you open the console in Standalone, which pauses the simulation, this added motion is apparent.

128 weather particles showing a bias in added motion, at 1000 FPS.

Speculating, this motion may have been added as a cheap way to avoid noticeable patterns like the same rain drop falling in the same place, since the simulation "wraps around".

Known issues

  • When the player is within a dense fog with a nearby opaque distance, weather particles will stop drawing even if set for the cluster containing fog. Ensure the opaque distance is sufficiently far away if weather particles in fog are desired.
  • Some features of this tag are framerate-dependent. See tag fields.
  • The added motion bias, described earlier.
  • Changing acceleration eventually gets stuck at 0 if 0 is the minmum bound.

Related HaloScript

Function/global

Type

(debug_point_physics [boolean])

Renders green or red markers wherever point_physics are being simulated. This includes flags, antenna, contrails, particles, and particle_systems. For weather_particle_system, markers are only shown in their simulation cube and while the weather global not disabled.

Red markers indicate point_physics with the collides with structures flag, which are more computationally expensive.

It can help to enable framerate_throttle for these markers to render consistently.

Global
(debug_sprites [boolean])

Renders 2D sprite effects like particles and weather_particle_system with white triangle outlines. This also displays some sprite statistics at the top of the screen (coverage and big sprites count).

Global
(render_psystems [boolean])

Toggles the rendering of particle_systems and weather_particle_system.

Global
(weather [boolean])

Toggles the rendering of all weather_particle_system. Defaults to true.

Global

Structure and fields

FieldTypeComments
flagsbitfield
  • Unused
particle typesBlock
  • HEK max count: 8

A list of particle types that are present in this weather system. As an example, the c10 swamp weather uses one type for rain and two types for flying insects. Note that the first particle type may use up the 512 weather particle budget if it's too dense, and other types will not render.

Particle types with identical fields will not spawn at the same locations, so this cannot be used to combine sprites in different orientations.

  • Processed during compile
FieldTypeComments
nameTagString

A name for the particle type. This can be anything and is only used to make identifying the type in Guerilla easier.

flagsbitfield

Boolean settings for this particle type.

FlagMaskComments
interpolate colors in hsv0x1

When the game gives particles a random color between the color lower bound and color upper bound, it will interpolate in HSV space rather than RGB. This results in intermediate hues being represented rather than the muddy mix that sometimes comes from blending in RGB.

along long hue path0x2

When interpolate colors in hsv is enabled, this causes the hue interpolation to go the longer direction. For example, if blue and green are bounds then purple, red, orange, and yellow will be present.

random rotation0x4

Particles spawn with random rotation, allowing for more visual variation despite using the same sprite. This applies no matter the render mode.

fade in start distancefloat
  • Unit: world units

The distance at which particles begin to fade in. This should be fairly close to the camera/player, but avoid having no fade at all or a distance of 0 since it can distracting for particles to come very close to the camera.

fade in end distancefloat
  • Unit: world units

The fade in distance where particles have reached full opacity.

fade out start distancefloat
  • Unit: world units

The distance where distant particles begin to fade out.

fade out end distancefloat
  • Unit: world units

The distance where distant particles fully fade out. This determines the dimensions of the particle type's simulation cube and affects the maximum achievable particle density.

fade in start heightfloat
  • Unit: world units

A world-space Z height where particles begin to fade in. Think of this as the lower bound. If you want the weather to be present throughout the level, set this and the fade in end height to some large negative number like -500.

fade in end heightfloat
  • Unit: world units

A world-space Z height where particles reach full opacity.

fade out start heightfloat
  • Unit: world units

A world-space Z height where particles begin to fade out again.

fade out end heightfloat
  • Unit: world units

A world-space Z height where particles fully fade out. If you want the weather to be present throughout the level, set this and the fade out start height to some large positive number like 500.

particle countBounds
  • Unit: particles per cubic world unit

Sets the density of particles for this type. All particle types must share the 512 particle budget, so arbitrarily high densities cannot be achieved for a given fade out end distance.

FieldTypeComments
minfloat
maxfloat
physicsTagDependency: point_physics

A reference to a point_physics which controls physical properties of the weather particles, such as their density, air friction, and more.

acceleration magnitudeBounds?

The amount of "forward" acceleration for each particle, used for particles that can accelerate on their own like c10's flying insects. Particles will be initialized with a random acceleration in this range. The particles' point_physics should have some air friction to avoid the particles accelerating indefinitely. Set the min/max to 0 if you don't want the particles to accelerate on their own (e.g. wind and rain).

However, if you intend to have acceleration and it changes with acceleration_change_rate, ensure the minimum magnitude is non-zero. For some reason, once particles randomly reach an acceleration of 0, they get stuck there and will not change back to higher values in the range, resulting in all acceleration eventually stopping in the weather particle system. This happens sooner at higher FPS.

acceleration turning ratefloat

Controls how quickly the particles change their forward direction. Setting this to 0 means they will always accelerate in the same direction, while numbers like 0.2 cause the particles to change direction and "wander". Turning is unaffected by the particle's visual rotation rate field.

This rate is framerate-dependent so particles will turn faster at higher FPS. This may result in particles not wandering as desired since they do not point in a given direction for long enough. Values up to 0.5 are recommended when targeting non-Xbox platforms so the turning is noticeble.

acceleration change ratefloat

Sets the rate of change in the amount of acceleration magnitude, between the bounds specified. If set to 0 the particles will only have the acceleration they were initialized with, while a value like 0.2 means they will sometimes speed up or slow down.

Like the turning rate, this is framerate-dependent. Values higher than 0.5 at high FPS result in the acceleration changing too frequently for noticeable speed changes in the particles.

particle radiusBounds?
  • Unit: world units

Scales the size of the particles, with the size being chosen randomly from this range. This is not purely a visual setting but affects the mass and surface area of the simulated particle, and therefore how it moves.

animation rateBounds?
  • Unit: frames per second

If the sprite bitmap has sequences, this determines the framerate bounds of the animation. Avoid negative values, which cause flickering in the particles.

rotation rateBounds
  • Unit: degrees per second

Sets the rotation rate of sprites, which will randomly be in either clockwise or counter-clockwise direction. This applies no matter the render mode, and does not affect acceleration if present.

FieldTypeComments
minfloat
maxfloat
color lower boundColorARGB

Lower bound for random particle color interpolation. The colors are multiplied against the sprite texture, and the alpha controls opacity of the particle. Set these colors to white if you don't want any color variation.

FieldTypeComments
alphafloat
redfloat
greenfloat
bluefloat
color upper boundColorARGB?

Upper bound for random particle color interpolation.

sprite sizefloat
  • Cache only
sprite bitmapTagDependency: bitmap
  • Non-null

A bitmap used for the particles, which must be sprites type. This bitmap can contain multiple sequences for random variation and animated particles.

render modeenum

Sets the orientation of particle sprites.

OptionValueComments
screen facing0x0

Particles will face directly toward the viewer, ideal for effects like smoke and snow.

parallel to direction0x1

Particles will be oriented along the direction of movement, facing the camera but only rotating around the axis of movement. This type is ideal for particles with trails like rain and sparks. In the sprite texture, right is the forward direction.

perpendicular to direction0x2

Particles will be oriented perpendicular to the direction of movement, so will be seen face-on when the particle is moving toward or away from the camera.

render direction sourceenum

Determines the direction to use for directional sprite orientations (parallel and perpendicular).

OptionValueComments
from velocity0x0

Particles sprites are oriented relative to their velocity vector. This is generally what you want, even for particles with acceleration. The random hard-coded motion added to weather particles

from acceleration0x1

Particle sprites are oriented relative to their acceleration vectors, making it look like the sprite is pointing in the direction it's trying to move. This should only be used when acceleration turning rate is low or else the rotation of sprites will be very jittery. The flying insect particles for c10 don't use this setting.

not brokenuint32
  • Cache only
shader flagsbitfield
FlagMaskComments
sort bias0x1
nonlinear tint0x2
don't overdraw fp weapon0x4
framebuffer blend functionenum

Sets how the particle will blend against the background. You'll usually want alpha blend for solid particles like snow, or add for glowing particles like embers. For alpha blend make sure your sprite bitmap has an alpha channel.

OptionValueComments
alpha blend0x0
multiply0x1
double multiply0x2
add0x3
subtract0x4
component min0x5
component max0x6
alpha multiply add0x7
framebuffer fade modeenum

Sets how sprites fade based on viewing angle. For directional orientations, fade when perpendicular can help avoid seeing the sprite as a spinning 2d plane when viewed edge-on.

OptionValueComments
none0x0

The faces do not fade by viewing angle.

fade when perpendicular0x1

The faces fade out when viewed edge-on.

fade when parallel0x2

The faces fade out when viewed flat to the camera.

map flagsbitfield

Flag controlling if the texture is filtered.

FlagMaskComments
unfiltered0x1

Texture sampling is unfiltered, resulting in aliasing at a distance and a blocky pixelated look up close.

bitmapTagDependency: bitmap

Secondary map reference used to color the particles, by multiply. This map's UV coordinates can be animated along each axis and rotated, with the fields working as you would expect from a shader tag.

anchorenum

Determines how the secondary map is positioned. If with primary, the sprite is multiplied atop each weather particle and follows its render mode orientation. The zsprite setting has unknown usage and may not apply to weather particles.

OptionValueComments
with primary0x0

Positioned relative to each particle.

with screen space0x1

Positioned relative to the screen.

zsprite0x2
flags 1bitfield?

Flag controlling if the texture is filtered.

u animation sourceenum

Function source for U animation. It's unclear what this would be connected to and may be unused.

OptionValueComments
none0x0
a out0x1
b out0x2
c out0x3
d out0x4
u animation functionenum

An animation function which allows the secondary bitmap to scroll in the U axis.

OptionValueComments
one0x0
zero0x1
cosine0x2
cosine variable period0x3
diagonal wave0x4
diagonal wave variable period0x5
slide0x6
slide variable period0x7
noise0x8
jitter0x9
wander0xA
spark0xB
u animation periodfloat
  • Unit: seconds
u animation phasefloat
u animation scalefloat
  • Unit: repeats
v animation sourceenum?

Function source for U animation. It's unclear what this would be connected to and may be unused.

v animation functionenum?

An animation function which allows the secondary bitmap to scroll in the V axis.

v animation periodfloat
  • Unit: seconds
v animation phasefloat
v animation scalefloat
  • Unit: repeats
rotation animation sourceenum?
rotation animation functionenum?
rotation animation periodfloat
  • Unit: seconds
rotation animation phasefloat
rotation animation scalefloat
rotation animation centerPoint2D
FieldTypeComments
xfloat
yfloat
zsprite radius scalefloat

Acknowledgements

Thanks to the following individuals for their research or contributions to this topic:

  • Conscars (Testing and documenting tag features)
  • Kavawuvi (Invader tag definitions)
  • MosesOfEgypt (Tag structure research)