Summary
This case study demonstrates a Niagara-based lightning system controlled by density or environmental conditions. The available showcases suggest a system that varies lightning behavior based on weather context, spatial density, or simulation-driven parameters.
System Breakdown
Density based lightning system with niagara is pretty fancy name and as you guess the system is also a little bit more complex than usual effects, to understand how the system works and how i did find the solution we need to take a moment and first examine how lightning happens and how volumetric clouds work in realtime renderers like unreal engine :
why Lightning happens :
Lightning happens when tiny ice particles inside clouds collide and build up opposite electric charges. When the charge difference becomes strong enough, Boom !! electricity jumps through the air as lightning. Dense clouds contain more water droplets and ice particles, which means probability that electric charges happens are much higher. so we need density ! when there is enough density in the cloud layer thats exactly where we want to spawn our Effect ! remember? from Boat Splash system case study that we can define a particle system by three terms : "Where, When, What" if we find the answers to these three questions we did solve the problem and we will have a functional particles system for our game/simulation.
How Volumetric Clouds work in realtime renderers:
Volumetric clouds in realtime renderers like Unreal Engine are not just simple planes with cloud textures on them, they are actual 3D volumes filled with density information. The renderer steps through this volume with a technique called ray marching and keeps asking: “how much cloud density is here? how much light can pass through? how much should be scattered toward the camera?”
Of course we cannot simulate every tiny water droplet and every single light bounce in realtime, that would be way too expensive. So engines use smart approximations, lower sample counts, noise textures, temporal reprojection and lighting tricks to make the cloud feel believable while still running in realtime. So again, the important word is density! if the renderer can read cloud density to draw and light the clouds, then we can also use that same kind of density idea to decide Where and When our lightning effect should appear !
Solution
"Where and when":
We need to expose the conservative density of our volumetric cloud material to niagara somehow ! unfortunately there is no direct way to send that data to a niagara system each frame, either we need to write the data to a render target and sample it in niagara or we can maybe calculate the same logic we have in the volumetric cloud material graph in niagara scratch module ! and sync those together! you may wonder if its possible to do replicate material graph logic in naigara scratch module !?? Yes it is possible! you need to consider that we are just calculating arbitery data on each pixel in the material graph and if we have a particle per pixel and do the same arbitery calculation we will lead to the same result! you just need to sync the data between the two which can be handled by a "Material Parameter Collection" (MPC from now on) and equivalent of it in niagara "Niagara Parameter Collection" (NPC from now on) NPCs can be linked to MPCs and you can control and update MPCs through blueprint functions ! so we solved the syncing problem !
Lets see how to replicate the calculation in niagara scratch module, I highly recommend organizing your material graph with named rerouts which are basically variables/containers, we will examine our volumetric material graph and deifne the inputs and outputs in between there are just arbitery operations and some texture samples ! and when you see "Absolute Wolrd Position" node you can just replicate it with "Particle Position" in niagara, Volumetric Cloud Component is just a box so you can spawn random particles each frame in a box with the same size of the volumetric cloud component box, also you need to find the flow of the calculation means which input needed in which function and order your functions accordingly in niagara scratch module, Unreal engine material graph will be compiled/processed in parallel but scratch module do have "MapGet" and "MapSet" so you need to prepare the data for the next function in volumetric cloud terms it means you need to first prepare for example your "3DPerlineNoise" Value then "CumulusNoise" -> "TillingNoise" -> ... the output of the scratch module would be a single float value called "ConservativeDensity" which we will write in each particle.
Then we will simply Do a Density Rejection pass in another scratch module and kill the particles that dont have enough density for the Lightning !
So we solved the lightning position with the density based system replicated in niagara scratch module so "Where and When" is solved but "what" to spawn ?
"What":
Lightning has to visual components -> Lightning Strike and Lightning Light/Emission spread across the volumetric cloud layer
Lightning Strikes are pretty simple, we have the particle position in cloud layer, we know the cloud layer bottom layer value from ground -> so we just scale the sprites uniformly from the cloud bottom layer to the ground and drive our Lightning strike material -> added a animation based on the particle age and some curves to control the look dynamically from niagara.
For the Lightning Light/Emission I chose to just write a 128x128 render target which loops through particles and for each 2D grid cell checks which particles are close enough based on some controllable radius, if particle is inside the radius create a distance based falloff light influence map around the lightning position -> then read that render target in volumetric cloud material graph, do some logic and connect it to emissive material property.
Ofcourse this was just a short summary of the system and it has alot of functions working in the background to make it possible.
My Role
My role:System design, Core features and ideas , implementation of the Niagara system and Materials, Coordinated the team to tweak the look and add UI controls and blueprint functions