This article is Part 2 of a series made from the lessons learned when making the “CPU-Driven Chaos Physics: Adding Eye Candy in Unreal Engine* 4” demo for SIGGRAPH. This part focuses on the Niagara particle system and walks through how to make efficient and visually stunning CPU particle systems.
Figure 1. SIGGRAPH demo.
Creating a Niagara System (CPU Ribbon)
To create a Niagara particle system, first create the component emitters that will make up the particle system. This has the advantage of allowing us to mix parts of our particle system into other parts of our game.
To create a Niagara Emitter, right-click in the folder view and select Niagara Emitter under the FX submenu. To follow this article, select the fountain basic emitter. We will modify this basic emitter to create the lightning effect to surround the laser bolts in our game.
Figure 2. Creating a Niagara Emitter.
With the emitter asset made, we need to open it and remove some modules we will not be using.
The Niagara editor breaks all the functions of a particle system down into blocks called modules. Each of these modules appears in an ordered stack on the right-hand side of the editor, which will be run in order from top to bottom. An example of how these might appear can be seen in Figure 3.
Modules are broken into categories called Emitter, Particle, and Render (shown in Figure 3 by background color). Modules in the Emitter Spawn and Particle Spawn categories are run once when the system is initialized, while modules in the Emitter and Particle Update section are run once per frame. To improve the performance of any Niagara particle system it is important to keep as many modules as possible within the Spawn category to reduce frametime cost.
For the electricity effect, we can remove many modules included with the fountain emitter. Before continuing, delete the following:
- Initialize Particle
- Calculate Size by Mass
- Gravity Force
In Figure 3 we can see what the stack looks like after removing these modules.
Figure 3. Electronic Niagara system after deleting unneeded modules.
Now that we have our clean emitter, we will need to modify some modules within it.
First, the Emitter Properties needs to set Interpolated Spawning to true and set Local Space to true, to ensure that if our emitter is moved it still maintains the same look as if it were a static object.
Figure 4. Emitter Properties module.
We will leave the Sim Target setting on the default value of CPUSim. When making a new particle system it is important that we set the sim target according to what sort of particle system we intend to make. If our particle system only uses a sprite renderer and basic scene depth collision, it is better to choose GPUSim. However, if we want our particle system to use more advanced features, such as lighting, scene collision, events, beams, and ribbons, we need it to be simulated on the CPU. While most modules will work on either mode, these features can only be run on the CPU.
Next, for the Emitter Update modules, we change the Spawn Rate module SpawnRate to 150. This determines how many emitter ribbons spawn every second. This value is easy to change, but it is important to know that the more ribbons spawned, the more performance the system will require.
The settings in Emitter Life Cycle affect how long the emitter runs before it turns off or resets. By default the module is set to turn off the emitter once there are no particles remaining. Since this emitter will continuously produce particles, it will run indefinitely.
Figure 5. Emitter Update modules.
Continuing, move down to the Render module so we can preview our particle system as we work on it. Add the NiagaraRibbonRendererProperties by selecting the top-right plus symbol of the Render module and, while the default settings will work, we still have to set the emitter. For this article, use the M_ElectricBeam material from the Beam Particle tutorial on the Unreal* Wiki.
Figure 6. Ribbon Render module.
With the Ribbon Renderer in place, add the Initialize Ribbon module to the Particle Spawn section by clicking on the plus sign in the section header and selecting it from the drop-down menu. In this module, we will give each particle a lifetime of 0.2 seconds and a nice red color.
Figure 7. Initialize Ribbon module.
At this point, our particle system should be producing a short vertical particle ribbon. Since our laser bolt will be traveling sideways, we want to change the Add Velocity module (to 1000, 0, 0); this will be the initial velocity of the particle.
Figure 8. Add Velocity module.
Figure 9. Preview after finishing the Add Velocity module.
Next, adjust the Sphere Location module Sphere Radius value to 5. This module spawns each particle in a random point within a sphere, and a smaller sphere will keep the beam closer together, like a single bolt of lightning.
Figure 10. The Sphere Location module.
Figure 11. Preview after finishing the Particle Spawn section.
Moving on, we need to add the Sample Curl Noise Field module to our Particle Update section. This module will give our ribbon a sense of directionality.
The order of modules is very important here because modules within a section execute from top to bottom. We need to ensure that the Sample Curl Noise Field executes before the Solve Forces and Velocity module; if not, we will not have a sample to apply to the motion of our ribbon. Modules can be reordered by clicking and dragging the header of the module.
Figure 12. Sample Curl Noise Field module.
Finally, we add the Curl Noise Force module, which will need to be between the Sample and Solve within our update stack. Setting the Noise Strength to 500 will influence the ribbon system enough to get the curling effect we want to see. With that, our emitter is complete, and we next move to creating the Niagara System itself.
Figure 13. Curl Noise Force module.
Figure 14. Final emitter.
We can combine our electric beam with our main laser bolt particle mesh to make the laser bolt look like it is bristling with unstable energies. To make a Niagara System, right-click the folder view and select Niagara System under the FX submenu.
Figure 15. Creating a Niagara System.
When creating the system, we have the option of assembling it from emitters present in our game project. To demonstrate how we can combine multiple emitters in order to create a Niagara System, in this article we will use a laser emitter that has already been created. This process can be done with any other emitter; the laser emitter just happened to be one we have on hand. Select Create a new system from a set of selected emitters and select both the Electric Beam and Laser emitters (or the Electric Beam Emitter and any other emitter). Add each one to the list for our new particle system by selecting the emitter from the list and then selecting the green plus symbol. Then finalize the process by selecting OK.
Figure 16. Creating a Niagara System from existing Emitters.
Figure 17. Initial view of emitters in a Niagara System.
When we first open the new Niagara System asset, both emitters will simply have been placed at the system’s origin. To fix this mismatch in size and position, we will tweak the values used in the electric beam emitter to fit our laser emitter. Ensure that we have the ElectricBeam emitter selected in the particle system Timeline that appears below the preview.
Figure 18. The Niagara System Timeline panel.
There are three properties we need to change about the electric beam to have it fit the laser emitter: length, direction, and diameter. All three of these can be set by changing values in the Particle Spawn section of the emitter.
We can set the length by changing the lifespan in the Initialize Ribbon module to 3 seconds. Set the direction by changing the velocity in the Add Velocity module (to 0, -1000. 0). Finally, the diameter of the effect can be modified by setting the Sphere Radius to 70 in the Sphere Location module. All these changes will only apply to this system, so we can easily have our original emitter used in multiple systems without having to create a new emitter asset for each one.
Figure 19. Particle Spawn section after being fitted to the particle system.
Figure 20. Particle system preview after fitting the Particle Spawn section.
While these changes made the electric beam emitter surround the laser emitter nicely, the tail end of the emitter spreads out more than intended. This can be fixed by setting the value of Noise Strength in the Curl Noise Force module to 100.
Figure 21. Particle Update section after being fitted to the particle system.
Figure 22. Final particle system.
One of the benefits to using the new Niagara particle system is that we can easily build new modules out of blueprints, which allows us to quickly and easily iterate on new systems. Together, we will see how we can leverage this system to increase the performance of a lit fire particle system.
We will start with a basic fire particle system, pictured in Figure 22. The full stack is shown in Figure 23, but all we need to know is that the particle emitter comprises CPU particles, which allows the particles to emit light.
Figure 23. A fire particle emitter.
Figure 24. The stack of a fire particle emitter.
First, we will add light to the particle system by adding the Niagara Light Renderer Properties module pictured in Figure 26 to the render section of our emitter. This does well to light our emitter, but it creates a performance problem. At any one time there are about 500 particles in this system. Having a light on all 500 of those particles, even if they are only simple lights, will be quite expensive. Therefore, we need to find a way to light only some of the particles in our emitter. Fortunately, the flexibility of the Niagara editor lets us build just that.
The first step to turning a portion of the emitter lights off is to enable the Particles.LightEnabled binding. This can be done by creating the variable and then enabling the binding in the lighting module. We can create the variable and give it a default value by adding it to the Set Variables module in the Particle Spawn section. This is done by selecting the down arrow on the right side of the Set Variables header, selecting Create New Variable, then bool. This creates a new variable called Particles.NewNiagaraBool that we need to rename to Particles.LightEnabled by clicking on the name once and typing the new one in. Our Set Variables module should now look like it does in Figure 25. Next, we need to enable the binding for that variable by checking the Light Rendering Enabled Binding option under Bindings in the NiagaraLightRendererProperties module. Ensure the right variable is selected by clicking the drop-down menu to the right of the check box and selecting the Particles.LightEnabled option. The NiagaraLightRendererProperties module should now look like it does in Figure 26.
Figure 25. Creating the Particles.LightEnabled variable.
Figure 26. The NiagaraLightRendererProperties module.
Now that we have our variable set up, we can create a module to light only a given percentage of the lights. We can create a Niagara Module in a similar fashion to other Niagara assets. Simply right-click in folder view and select Niagara Module Script from the FX menu, as pictured in Figure 27, and name it LitPercent.
Figure 27. Creating a Niagara Module asset.
When we open the module asset, we first have to create the variables that we will use to manipulate the particle lights. In the Parameters panel, click the plus sign next to the Module section and select float from the menu that appears, as in Figure 28. We will use this parameter to control what percentage of particles are lit. Name it Module.LitPercent. We will repeat the same process for the particle section of the Parameters panel, this time choosing bool from the menu and naming the resulting variable Particles.LightEnabled. This is the variable we bound earlier that will determine whether the particle is lit or not.
Figure 28. Creating a parameter.
Finally, create the node graph shown in Figure 29. It will generate a random float number between 0 and 1 and compare it to our Module.LitPercent variable to determine whether the particle should be lit or not. Picking a random number here will make the number of particles lit fluctuate from second to second while staying close to the desired lit percentage. This serves to make our fire have a more chaotic feel to it, instead of producing perfectly even light.
Figure 29. The node graph for the LitPercent module.
Now that we have finished creating the module, select Apply in the upper-left section of the editor window, as shown in Figure 30. All that we have to do now is add the module to our editor.
Figure 30. Applying the module.
Adding the module to our emitter is as simple as clicking the plus sign in the Particle Spawn header and selecting Lit Percent from the list. The Particle Spawn section should now look like it does in Figure 31.
Figure 31. The stack of a partially lit emitter.
Now when we use the fire emitter, we can choose a value between 0 and 1 to control how many of the emitter’s particles are lit. Bringing that value to 0.5 drastically reduces the amount of time the particle system takes to render and can be finely tuned to make the fire appear more realistic. In Figure 32, we can see what different Lit Percent values look like next to each other. As we can see, the number of lit particles can be greatly reduced before it impacts the visual fidelity of the effect.
Figure 32. Different Lit Percent values.
Other CPU Particle Features
One of the most versatile features of Niagara CPU particles in Unreal is events. Using these, we can enable particles within a system to interact with each other. In the example in Figure 33, we can see a particle system with three emitters. One emitter produces the cloud of smoke at the center of the explosion while the other two work together to produce the burning trails that fly forth from the explosion. It accomplishes this by using one emitter to release a burst of particles that are invisible, but that broadcasts location events to the whole particle system. The final emitter listens for location events and will emit flaming particles at the location specified within them.
Figure 33. A particle system utilizing CPU particle events.
Another useful feature of CPU particles is collision. This allows particles to interact with the rest of the scene in a way that is not possible on the GPU. This is because GPU particle collision uses the depth buffer, and is dependent on where the player is looking. We can see an example of this in Figure 34. On the right, there is a platform between a colliding particle system and the player in such a way that it does not touch the particle system. The particles interact the way that one would expect and do not interfere with the platform. However, the GPU particles on the left treat any area not visible to the player as solid, and so can sometimes interact with the scene in unexpected ways. Figure 35 shows the same scene from another angle where the platforms are no longer in front of the particle system from the player’s perspective.
Figure 34. GPU particle collision on the left, CPU particle collision on the right.
Figure 35. Figure 34 viewed from another angle.
Coming in Part 3
In Part 3, we will look at how to get the most performance out of the new Chaos systems available to us. This includes techniques for using Chaos destruction efficiently, and how to diagnose problems with the Intel® Graphics Performance Analyzers.