Pages

Friday, August 08, 2014

UDK Spreading Fire Actor Tutorial

NOTE: Feb 2015: I'm working on an updated version of this tutorial with better performance and flipbook-based particles.
March 2015: Updated Example Files link. 



I've been working on this off and on for a while now and think it's ready to share (but still not completely finished). It's an Actor-based class written in Unrealscript that simulates fire spreading based on a map's wind direction and the flammability of surrounding materials. It's not really a physically accurate simulation, but the effect is fun to watch and can be used strategically in gameplay.

This version works with a WindDirectionalSource actor to provide it with wind variables. In my project's version, it ties in with a weather system actor to handle cleanup and make it respond to rain, as well.

I'm including a long description of the logic for anyone that wants to implement something like this in other languages/engines.


Older video showing what this does:
Youtube

Requirements
  • DynamicEmitter_Spreading and DynamicParticleEmitter_Fire classes provided in this tutorial
  • a custom physical material property class with a variable representing flammability
  • a WindDirectionalSource actor on your map
  • a custom light function class to be assigned to the LightComponent this uses (a basic flickering effect like this (link) works)
  • a particle system for the actual fire and smoke with a parameter for the smoke's velocity over time (instructions at the end of this tutorial)
  • a looping fire SoundCue with a high radius


Code + Assets




NOTES:

- You will need to assign a PhysicalMaterial with a custom PhysicalMaterialProperty (example class is included) that includes a flammability variable to surfaces you want the fire to be able to spread to.

- By default, debug lines will be drawn to represent the path the fire is taking. This can be disabled by setting bShowDebug in LudEmitter_Spreading to false.

- The emitter is not currently placeabe in the editor, so it must be spawned in code and initialized with a call to InitSpreadingEmitters. I did it this way because the functions the emitter uses to spread and grow are not available in editor mode.

- I haven't gotten around to making the flames climb walls, but this is a planned feature that I will be adding to the tutorial when I get around to it.

- It's not currently working in multiplayer but includes some of the functions required for replication. I haven't focused much on this since my game has no multiplayer modes for now.

Logic

LudEmitter_Spreading.uc:

This actor consists of the logic required to spawn and pool the particle systems, a PointLightComponent and an AudioComponent. The light component is offset upwards a little bit to lower the chance that it will intersect with the landscape or ground meshes.

In order to start a fire, the actor needs to be spawned and initialized with a call to its InitSpreadingEmitters function to give it a Controller it will use as the instigator for any damage it causes and to initialize the variables it needs to function. The function also creates a reference to the WindDirectionalSource it finds on the map.

Once initialized, the main actor starts three timers:
ContinueSpreading – The 'main loop' that checks if another particle system needs to be created, spawns a new one if required, and calculates the new center point to move the main actor to.
RemoveFireTimer – This one will only execute once fTotalTime has been reached and starts the cleanup procedure.
UpdateWindTimer – Updates the wind direction and speed for each particle system in the pool.

The fire finds new locations to spread to with the GetNewSpreadLoc function, which is called in ContinueSpreading. This function performs traces in each direction specified in vTraceDirections and gathers the variables associated with the found spot. Before the traces are actually performed, the dot product of the next trace direction and the wind direction (with Z for both set to 0.0) is calculated. The actual traces are only performed if the dot product >= 0 to lower the amount of traces that need to be run (also to limit the spread direction to within 90 degrees of the wind's direction). If the wind's strength is high enough, a spark jump is simulated by increasing the trace distance. This is determined by a floating point variable that stores the maximum strength the wind can reach on the map (fMaxwindStrength).


The physical material of each spot is queried for its fFlammability variable, which is used in the following formula if it is greater than 0 to determine the probability of the spot being picked:

((WindDirection . SpreadDirection) + fFlammability) / 2.0

This increases the chance of fire spreading in a direction depending on how close it is to the wind's direction and is also scaled by the flammability of the spot's material.

Here are some example fire spreading distributions under different conditions. The first image represents the base chances per direction when there is no wind and the materials surrounding the actor have equal flammability ratings. The second one shows the distributions when the wind facing to the north-east and the surrounding materials have an equal flammability rating. The last one shows a more typical scenario with variable flammability on surrounding materials and NE-facing wind. In these images, the green dots represent the spot that would be picked if no simulated sparks are launched from the fire by high wind, and the blue dots represent the spot picked if a spark is launched. The wind strength in the second and third image is assumed to be at maximum.

No Wind, Uniform Material
NE Wind, Uniform Material
NE Wind, Different Materials

Each time a new spot is found, a custom particle system actor is spawned and the new center point for the current cluster is calculated (function GetNewCenterPoint). Since the main actor includes the sound and light components for the system, the actor's location is set to the new center point to line up the effect with the particle systems. As more particle systems are spawned, the sound's volume and the brightness of the light are scaled, as well. This is calculated at the end of the function CreateEmitter.


LudDynamicParticleEmitter.uc:

The custom particle system actor contains the logic to change the parameters required for the smoke's wind direction and the size of the particles emitted over time to simulated the fire's growth. The whole idea is that the particle system actor only handles the essentials for displaying the fire, all math that comes up with the values is done in the main actor.

Fire damage is handled by a collision cylinder in this class that is set to receive only touch events. A timer function damages any touching actors. My project uses a damage over time system to make damage more consistent, which I won't share at this time since it's outside of the scope of this tutorial.


 
Particle System Setup:

Dynamic changes to the particle systems used in this are handled by Particle Parameters (UDN link) that are altered in real-time by Unrealscript.

Note on Materials:
There is a strange bug that was causing particles to disappear at some viewing angles that I could only partially fix by enabling Screen Door Fade on the materials for the flames and embers, and disabling it on the smoke. This would happen on any other combination of the two, including when it was disabled on both. Changing the sorting modes of the emitters also didn't help with this.
This is not fully fixed, so you may see the flame emitters flickering when looking at them from certain angles.

The particle system I'm using for this uses four emitters, but only the first two are actually required for the wind and growing effects:


- Flames

I decided to use a different approach than the commonly used floating red smoke effect seen in most games. Since real fire is a constantly shifting, flickering mass, I decided to create particles for it that mimic this by growing and shrinking throughout their (short) lifespans. At any time, there are about 4-8 of these particles overlapping to simulate the shifting effect. Earlier versions used a custom depth bias effect to blend the flames with their surroundings, but that approach proved too expensive for larger fires with lots of flame emitters.

The material for this particle is a basic emissive sprite with a texture that contains four (in this example) fire shapes handled by the particle emitter's SubUVs. The blend mode for this material is set to Additive to create a fluid-like effect of flames being blended into one mass.

The particles should be created with a slight upwards Initial Velocity. A particle parameter (named 'ParticleSpawnSize') for Initial Size that will be altered in script throughout the emitter's lifespan (grow, then shrink) should also be included. Size by Life should be set up for the particles to grow/shrink throughout their own lifespans. Color Over Life is optional, and can be used as a multiplier to increase the intensity of the flames' color.


- Smoke Column

This emitter is going to be visible most of the time, and will have the biggest performance impact. It's also the only one that's affected by the wind's direction and strength using a particle parameter (named 'SmokeVelocity') applied to the Initial Velocity module. A Velocity/Life module speeds up the particles' X and Y axis movement while scaling down movement along the Z axis to allow the smoke to become more dense at the top of the column. The sort mode I'm using for this one is Age_NewestFirst, which gives the smoke a better illusion of volume.

The material I'm using for the smoke effect is a bit heavier on performance since it's using a custom depth biased alpha effect to blend it with the environment. The smoke's opacity is subtractive to make it look like it's dissipating instead of fading out. The material also creates a rounded black border, which is multiplied into the alpha channel to smooth out the particles' edges. The lighting model for the smoke is Unlit and the Blend mode is set to Translucent.

The texture was created by generating some tiling greyscale cloud textures with Gimp, and placing them into the RGB channels of a new texture. Only the R and G components are used in the material, and are set to pan slowly in opposite directions to add more variety.


NOTE: The following two are best limited to the first LOD since they can be pretty performance-intensive when a large fire with lots of particles from these emitters is on screen.


- Embers

This emitter creates embers flying in random directions that spin around and fade from a bright red to dark grey. It uses a very basic unlit material with a 32x32 black texture with a white streak in the center. It also uses an orbit module to create curved paths for the particles.


- Ground Smoke

This one uses the same material as the smoke column emitter, but spawns particles at a slower rate and in different directions. Particle are spawned with a random velocity on the X/Y axis and a low positive Z velocity. Size by Life is also set up to make the particles grow as they are fading.


3 comments:

  1. the link to the assets isn't working.

    ReplyDelete
    Replies
    1. Thanks for letting me know. I'll look into it.

      Delete
    2. I've reuploaded the file and updated the link in the post, sorry about that. I'll look into some more permanent file hosting in the near future...

      Delete