Massive 3D Particle System in Flash Molehill
Evolution of Molehill
I’ve been working on Molehill for more than a year now.
Since the very first iteration, to what we have now… wow there was a huge evolution.
- Evolution (countless changes) in the API and features
- Evolution in performances
- And a lot of evolution in the community.
An old thread
can you remember the debate about PixelBender vs pure AS3 vs haxe?
Let me help you remember! There was a nice attempt by a lot of people on the net to do a massive particle system with flash.
A lot of comparison have been done between different way by the “masters”, and to honor theses efforts, I tought I’de make something with Molehill out of this old thread.
PixelBender+Alchemy option (by Ralph Hauwert)
Pure AS3 option (by Joa Ebert)
Revamping an old post
It’s always fun to play with particle system when using a new tech.
Today I’m presenting to you one of the very first proof of concept I made with molehill, using a technique we developed at Frima Studio. (Already one year ago!)
So I went in my archive and fixed all the API changes that were made since then.
There was also an old blog post going with it that I never released due to the “to early stage” of molehill pre-release, and the technological advantage of open-sourcing such as technique.
But since then there was a lot of development… First the presentation at Adobe Max 2010 of the ZombieTycoon trailer, Then The featured release of a couple of Zombie Tycoon levels, the session at Flash Gaming Summit 2011 and the session for the San Flashisco user group. And internally at frima, the tech never stopped to grow!
We are going to present at Adobe Max 2011. I’m sure it’s going to be awesome this year (again!).
The Particle System
This is a very simple particle system.
The particle position are defined using a classic “Strange attractor” algorithm.
Each particle is made with a quad and is facing the camera (Billboard)
THE most important thing when doing a particle system is to have a good batching process.
Particles are often in very high numbers, and they must be drawable in batch to keep the performances high enough.
When we first started thinking about it, it was pretty obvious that to create something nice with billboards, we would have to transform each quad to make it face the screen (Transform by the Inverse ViewProjMatrix). While this might sound obvious and simple to do, when processing the vertex in a vertex shader that process them one by one with no index or whatsoever defining what corners we are processing, it’s not “that” obvious!
The transformation needed on the four corners of your quad is not the same! but you can only define “one way” of doing things in your shader. (No if statement). Hence, if you can’t differentiate what you are processing, how can you make the good transformation to each vertex??
After a couple iteration where the CPU was doing the matrix transformation and re-uploaded each position each frame… We went in another direction. (It was WAY to heavy!)
The vertex shader let you define constant that you can access within the shader. Sadly, you have only 128 Float4 of theses.
So no real way of “batching” large amount of particles by making a list of transformation for each vertex. The best you could do is a couple of dynamic particle at the same time.
The thing you can do is mix between your vertex arguments (position, scale, uv, etc. defined for each single vertex ) and the Vertex shader constants (limited).
In your vertex arguments, you can define an ID for each corner of a quad: 1,2,3,4.
Then, assign the exact same 3D position (center of the quad) to all 4 vertex.
By setting only one position (4 time the same position) it means that it require the exact same transformation for all corners of your quad. (yeah!) But then, you have to be able to “re-construct” your quad inside the shader
In the Constants, you define an offset.xy from the center to each of the corners.
And then, when processing the vertex in the shader, it can read the ID of the current vertex, which can then be use to access the offset matching the current vertex in the constants.
You can now recover your quad by offsetting the center of each vertex (Yeah #2!)
So the final algorithm is:
//VertexShader position = argument.xyz // Center of the quad id = argument.w //ID=1 | 2 | 3 | 4 Offset = Constants[id] transform the Offset of the current corner by the Inverse ViewProj Matrix //billboard Add the result to the vertex position transform finalPosition by the ViewProj Matrix //Show on screen
The technique used here is to modify the UV of each particles in a bytearray, and send it back to the Video Card.
for each(particle in particleList) Set Vertex1.uv = particle.nextframe() Set Vertex2.uv = particle.nextframe() Set Vertex3.uv = particle.nextframe() Set Vertex4.uv = particle.nextframe() UpdateVertexBuffer(ParticleList)
The same result could be achieved using a full GPU particle system. with the UV changing over time using an offset in function of time.
But to represent a system where each particle would move independently with physics for example, it was best to re-upload the whole thing.
the texture is a space-core SpriteSheet (sphere with rotating rings around)
The format original was a PNG with transparency
I decided to split that up in two, and compress them with the ATF file format.
As you can see, the background is black.
To be able to use transparency, I made a alpha mask for it:
I could have used the original png, and kill transparent pixels.
But to do that I need a texture with 4 channels (RGBA). Which means that I cannot use ATF texture compression.
After benchmarking it, doing a sampling in two ATF is faster than doing only one in a uncompressed bitmap.
Hence I went with the compression (and of course, not only it’s faster, but smaller in video memory)
One of the goal of this demo was to determine what was the balance between process on the CPU and GPU.
Don’t forget to use the latest Flash Player 11 Incubator build
If you think of better/other ways to do the same thing, please comments in here! Sharing is good 🙂
I know you guys are hungry for some code!
Just imagine what we are able to do right now, and how this is going to change the face of the gaming industry!
Yup! I am about to release a new version of FlashPreloadProfiler. It’s now very complete and I will be proud to release it in a couple of days! I hope you will stay tuned!