2017年10月15日 星期日

Thunderbolt Particle System in Unity.

Recently I want a thunderbolt effect in my game.
I hope my thunderbolt can emit randomly and interact with skybox (to lit the skybox).
Thus the proposed system is created.

Thunderbolt Calculation

The idea is simple, prepare a quad with a thunderbolt texture.
Duplicate the quads and connect them all together.
Fig.1 illustrates the idea.

Figure 1. Thunderbolt quads.

And the input thunberfolt texture should be like this:
Note that the branch of thunderbolt and the halo around thunderbolt aren't necessary.
Since my program will calculate it (I can't find a good texture for sample).
So prepare a texture with main thunderbolt and put it on the center of texture.
My system will connect the center point of the quad.

  
Figure2. A single thunderbolt quad.

Next, my system creates a set of random vertices for rendering thunderbolts.
By using the method Quaternion.FromToRotation(), we can calculate all random vertices and give them random directions.

Since this will cause CPU spike in a frame, I put this job on another thread.
After my system call Monitor.Pulse(obj), the worker thread will wake up and calculate these vertices. If worker thread is done, it will call Monitor.Wait(obj) to sleep.

For performance, my system put point primitives (a vertex is a point) to mesh filter only.
Instead, my system form a quad in Geometry Shader Stage.
This can reduce the CPU calculation to a quarter.

And this is how my thuderbolt emitted.

Halo Calculation

Figure3. Thunderbolt with halo around it.

For thunderbolt halo, my system render another pass for this.
It uses the same vertice as thunderbolt, but passed to another shader.
Basically the formula is like the point light attenuation, but my shader calculates a oval-ranged attenuation. So that it can fit my thunderbolt.


Figure4. Oval halo piled up together.

It doesn't look like oval, huh?
With this calculation, thunderbolt halo works properly.


Skybox Lighting

The last thing in my system, how to lit the skybox?
First, we have a skybox cubemap. And of course, we need to prepare a sky normal box.
With this sky normal box, we can use normal lighting model on it.

 Figure5. Sky normal cubemap.

But we know skybox is a huge cube and it can be scaled to 2000x (even 5000x).
We can't get a good calculation of lighting with 3D distance.

Instead, my system calculate the skybox lighting with screen space distance from thunderbolt root to the vertex on the sky for attenuation.

It's recommended to design sky normal map with a fixed directional light. 
We also need to specific thunderbolt lighting direction in script for a consistent result on the sky. (Fig 5. is a bad example since I get this from normal generator)

Thus the size of the skybox doesn't matter. 
We can get the lighting we want!

Demo



You can buy this asset on Unity's asset store: