Work   














Firework(pyro)

research







TYPE:
FX


SOFTWARE:
· Houdini
· Unreal


POINT:· Pyro
· Flame simulation
· Houdini - Unreal workflow
· Zibra VDB compression tool
· Houdini Pyro render









Week 0 - flame approach and Zibra test






This is a 4-week Pyro simulation project aimed at real-time rendering.
Before starting the project, I need to do some preparation — I need to understand how flame simulations work in Houdini and how to export them, as well as how to import VDB models into Unreal Engine 5 using Zibra. Once I’ve confirmed that this workflow is viable, I can move forward with the project.



1. pyro and flame simulation

I looked through some tutorials on fire effects and found that both fire and smoke simulations are based on Pyro. The methods for creating them are almost identical.

First, use Pyrosource to convert the object serving as the emission source into a point cloud. You could also use other methods to convert polygons into points, such as Points From Volume, but we recommend using Pyrosource directly. This is because it automatically creates the attributes you need.


 

The density attribute is clearly the key factor. Both smoke and fire use this attribute as their emission source. The temperature and burn properties control the shape of the flame.

Here’s a simple example illustrating how these three parameters control the flame by default: 
density controls the density of the pyro and also affects how it is affected by gravity and force; 
temperature controls the temperature within the area, where pyro activity is more intense in areas with higher temperature weights; 
and burn controls the shape of the area emitting the flame.


density
 
temporature
 
burn


 

We then use Volume Rasterize Attributes to convert the points into a VDB, which serves as the input for our solver. Note that the attributes we created earlier will be converted into VDB attributes as they pass through this node.

 





In this tab of Pyro Solver, you can see how to use attributes to control the target field. This allows you to use custom attributes to control the field.
















And how to shape the flame. If you want to set up a specific wind field, you need to dive into the solver node and use the force output as the output node.



Before learning about fire, I thought that “fire” and “smoke” are two different things that need to be created separately. In fact, they are both types of pyro, and fire and smoke can be created together by the Pyro Solver. The Solver(sparse) is a solver specifically designed to generate smoke within a dynamic region, which means the solver checks and crops out areas without smoke in every frame. In general, the result of the calculation will take up less memory but it seems this might also slow down the processing speed.

nodes of pyrosolver(sparse) and pyrosolver
 
left - pyro sparse;  right - pyro flame smoke


*Update: Running Pyro simulations here in Dopnetwork isn’t a good idea. A better approach is to use DOPNetwork at obj level or to use PyroSolver for smoke simulations. Using Dopnet within Geo isn’t straightforward - it requires DOP Import Field to view the results. Furthermore, micro-solvers would be more suitable for complex situation.


2. Zibra Pre-test

Before begining, make sure all the necessary plugins have installed. I’ve included some resources that might be helpful here. Although Zibra is free, you still need to activate a license to use it. Please visit the official website for instructions.

· Sidefx - Zibra instruction page:
  ZibraVDB for Houdini

· Zibra official website for Houdini plugin:
  Download ZibraVDB for Unreal Engine | Real-Time VDB Compression Plugin

· Zibra - Unreal 5 instruction page:
  https://zibra.notion.site/ZibraVDB-for-UE-1-5-2fdbc784cfb380e0b041ff9fea634d82

· Zibra Unreal 5 plugin FAB link:
  Plugin for VDB Compression and Real-Time Rendering — ZibraVDB (Personal Tier) | Fab

· Zibra  samples:
  ZIbraVDB Sample Effects



Using Zibra isn't difficult. The plugin uses a special filecache to store VDB data. Compared to a standard filecache, using this one may avoid some unnecessary trouble.

The file extension for the filecache will be .zibravdb. You can use ROP to further compress the filecache. This step may slightly degrade the quality, but usually not by much.



compare the size before and after compressed



So it seems that both Pyro types can be successfully imported into Unreal 5 via Zibra. The issue is that the fog density and color look different from how they appear in Houdini. However, these can all be adjusted within Unreal.

 
import to Unreal 5
houdini pyro sparse
houdini pyro



The official documentation outlines two different approaches: including pyrolook before filecache, or omitting it. The advantage of the former is that minimal adjustments are required after importing into Unreal; the advantage of the latter is that it offers greater flexibility for customization within Unreal.

 
Zibra Houdini file -  compress
Zibra Houdini file - Pyro Bake OptionA
 
Zibra Houdini file - Pyro Bake OptionB



              final result
         


 

The color of flames and smoke can be adjusted directly in Unreal. The corresponding Houdini attributes for density, flame, and temperature are density, burn, and temperature.



Week 1 - Start






Topic choice: To create something suitable for the Zibra process, it’s best to look for reference with more smoke and fire. Therefore, fireworks would be a good choice in this case.

Reference: firework (click here to watch the video)

To know how to do it, it’s best to first understand how fireworks work:
An animation for firework explosion theory


Observe:
As you can see, there are explosion, fire, smoke, sparkle.

So the rough idea is to use -
1. RBD bullet for launching firework powder;
2. Pyro for smoke and fire;
3. POPnet(or Unreal Niagra particle) for sparkle.

4. Pyro burst for explosion

Step 01 - Modeling

So the first step is modeling. there’s no difficult models in the scene but I have to guess the structure of the firework launcher. The video shows that each box contains four shells. After launching the shells, it emits a second round of small sparks(later do this as particle).





Step 02 - Explosion

Set a source for each emitter. I used a circle as the source because the flames appear cylinder-shaped. Use Enumerate to create an index for each instance. I named the index attribute explosionid. Then use this attribute to control the startframe — create a startframe attribute using Attribute Adjust Float, and set the max value as three times the source range (I have 28 instances here). This will result in a startframe that gradually increases in 3-second increments.



Quickly generate an exploding particle cloud using the Pyro Burst Source. Use Volume Rasterize Attributes to convert the particles into a volume (don't forget to enter the source attributes in the Attributes blanket).



Use the previously obtained emission source(the circle array) to trigger the explosion. explosion will be triggered every 3 frames in order. BurstSource actually outputs a static point cloud rather than a DOP result, but rapid scaling and fading are sufficient to create an explosion effect, so it can be exported directly without the need for DOP simulation.

point cloud view (Pyro Burst Source)
explosion flipbook
explosion view (Pyro Look)




The explosion will produce smoke. Unlike the smoke from fireworks, this smoke is denser and will settle to the ground and spread out. Therefore, use the point source from earlier to run the DOP simulation. In DOP, use Pyro Sparse to simulate the smoke.
If you're unsure how to configure the volume source to drive the target field using attributes, simply select “Initialize-Source Smoke” at the top of the volume source; the node will automatically set up the preset attributes and corresponding fields.  Here, I add an option using “burn” to control the target field “divergence”, meaning that the higher the burn value, the more the smoke expands.





Step 03 - flame

After the explosion, the launcher immediately shoots out flame. If flame is generated using regular methods, it moves too slowly; using the explosion method described above doesn’t produce dynamic flame. So I came up with an idea — why not combine the two approaches? By using a pyro burst source to generate a sudden burst of particles, and then using those particle clouds as a pyro source to create flames, this produces flames that appear to erupt suddenly.

 
pyro burst source


 
volume rasterize attribute


 
pyro solver



* Pyro Burst Source setup
Unlike before, the burst type needs to be changed to “muzzle flash.” Also, various sizes need to be adjusted. Another very important point is adjusting the frame duration and expansion, which will determine the duration and shape of the flame.



At last use Pyro Bake Volume to give the fire a final look.





Step 04 - Launcher RBD

According to the reference video, each box should hold four shells, and they should be fired one after another rather than all at once.

Since my four shells are instances generated by Copy To Points, when I run an RBD simulation after entering DOP, these four instances will be launched simultaneously (because they belong to the same object). So the question is: how to trigger the launch in the correct order?More specifically, how to fire a shell every 0.25 seconds?


Approach 01 - Active attribute + DOP network

Use the “active” attribute to activate instances one by one. The idea is to assign an “id” attribute to each instance, and then every 0.25 seconds, change the “active” value from 0 to 1 for the instance with the corresponding “id”. Once activated, set v to (0, 8, 0).

Result: I can’t set up “active” attribute this way. DOP can read the “active”, but it does not seem to be applied correctly to every instance.

velocity VEX
active VEX
  

Approach 02 - RBD Key Active in DOP network(suggested by Chat GPT)

Chat GPT recommand me this method: use RBD Key Active in DOP to activate the emitter objects one by one.
Fill expression in Active Value and Activation blanket. That means objects are activated every 6 frames based on their names.

Result: I can’t run RBD Key Active correctly - As we know sometimes AI will give out wrong solution.





Approach 03 - Startframe attribute + DOP network

Use the Attribute Adjust Float to set individual startframe for each instances. The idea is to use “start frame” to control the activation time for each instance in DOP.  

Result: I can’t set up “startframe” attribute this way.




Approach 04 - Activation + RBD bullet solver

Same method as the first approach, but give up DOP network and use RBD bullet solver instead. This node inherits attributes from upper stream, and in fact, “active” does work correctly this time, but this solver doesn’t have an initial speed feature.  

So I created an additional velocity attribute “v”. However, “v” maintains the ball's velocity, preventing it from being affected by gravity. So I added a condition to make the velocity effective only on the first frame, but this caused the subsequent upward velocity to drop to zero.


Result: I can’t set up initial velocity this way.







Week 2 - Pyro






This week, the issues from last week have been resolved. Special thanks to Professor Deborah Fowler for helping me solve this problem.
Her solution is - use the SOP solver in DOP to set “active”, then the shells will be successfully launched in order. Later I set “v” in the same way, which will give initail velocity to each instance.

Conclusion: Use SOP solver for instanced objects.





Step 05 - Firework smoke


At first, I planned to use the shells directly as the pyro source, but their high speed caused the smoke to break up. So I used Pop net to emit particles and used those particles as the pyro source. This made the smoke much more continuous.

                   


Observing the reference animation, note that the smoke at the top of the firework moves very slowly, while the smoke at the bottom swirls and expands rapidly. Therefore, set a range for the temperature so that the smoke at the bottom is higher. Here, I use a sine wave to make the transition smoother. At the same time, temperature is also used to control the velocity.

velocity
temperature
density


Use a “for each” loop to replicate the effect of launching every 0.1 seconds

     




Week 3 - Modification






I finished the firework smoke simulation this week, though the smoke may still need some adjustment.

To match the shape of the smoke in the reference, I refined my approach: I used the Pyro trail path to generate emission trails, then rasterized these trails to convert them into a VDB, and finally merged them with the VDB of the fireworks smoke.




The final result will look like this. Similarly, this method can be used to create small fragments and spark trail smoke.



To make the smoke less uniform and ensure it is influenced by wind and turbulence, I duplicated the source seven times before running the Pyro simulation. This allows me to obtain a complete set of smoke simulations. But at the same time, it’s very expensive. I also add a bit of random scale for each iteration so the smoke will not look too regular. My computer’s memory can’t handle such a large simulation, so it always crashes around 150 frames.

           
for each duplicate
 

I tried using Pyro Bake Volume for shading(or, to be more accurate, coloring), but the results weren’t great.
First, even if I use Pyro Bake Volume for coloring in Houdini, the colors aren’t carried over when imported into Unreal, so I have to do the shading in Unreal anyway.
Second, Zibra doesn’t read custom attributes in Unreal, so I tried using the temperature property to create a mask in Houdini, but it didn’t work well.


     
simulation
Houdini coloring
Unreal default coloring
Unreal coloring
temperature mask


The logic of coloring is different in Houdini and Unreal.




Step 06 - Zibra

I met one issue here: Zibra does not support compressing more than 8 channels. These 8 channels include point, primitive, detail, and VDB, so ensure that attributes are deleted until there are fewer than 8 channels remaining.

 

Zibra is no different from a standard filecache; the only thing to keep in mind is the compression ratio. Different sizes of smoke suit different compression ratios.



Step 07 - Pyro in Unreal 5

A single firework smoke filecache is 36 GB. After Zibra compression it is 1.6 GB. So when I put four smoke into scene Ureal is exhausted.
At the same time an issue arises - the smoke exhibits strange moving in the final few frames.





Week 4 - Rendering






Step 08 - Pyro final rendering in Houdini

My computer has limited memory—only 64 GB—so I can’t cache too much smoke. That’s why I’ve divided the smoke into four groups by color, simulated each group separately, and then duplicated them. This also makes it easier to shade.



Although the mask I created earlier using the “temperature” attribute didn’t end up being useful in Unreal, it can still serve well in Houdini. In the Material Library, create a Pyro material and use my favorite node, Mtlx Geometry Property Value, to import the attribute mask (in this case, temperature) to control the smoke color.




Final render

still render
  
comparison



Because the project was too large, I had to split it into two segments for rendering. When exporting the second segment as a USD file, my memory ran out, causing Houdini to crash and bringing down my computer system as well. Keep an eye on the export status—this is something to watch out for in future work.

Apart from that, there is still plenty of room for improvement in the project as a whole. Many thanks to Professor Fowler for her suggestions - the smoke may require an adjustment to the disturbance value. Additionally, the variation in voxel size caused by the merging of several pyro sources may be one of the reasons for the excessive difference in smoke density between the upper and lower layers, which is worth noting.




                                          - END -





Entire contents copyright © 2020−2026, Burson Lin
All rights reserved




















  



                                                                                                                               
                                                                                                                                                                   
Go Top