A particle system is a technique in game physics, motion graphics, and computer graphics that uses a large number of very small sprites, 3D models, or other graphic objects to simulate certain kinds of "fuzzy" phenomena, which are otherwise very hard to reproduce with conventional rendering techniques - usually highly chaotic systems, natural phenomena, or processes caused by chemical reactions [Source: Wikipedia]
The Particle System that I am providing here has a platform specific implementation for both OpenGL and DirectX. There is an easy to use, platform independent implementation on top of that. That interface can be extended in C++ and also in Lua.
The source project can be downloaded here. To begin using this Particle System, follow these steps:
GetBuilderRelativePath = function()
RegisterReferencedAssets = function( i_sourceRelativePath )
local sourceAbsolutePath = FindSourceContentAbsolutePathFromRelativePath( i_sourceRelativePath )
if DoesFileExist( sourceAbsolutePath ) then
local file = io.open( sourceAbsolutePath, "rb" )
local fileContents = file:read("*all")
includes = (load (fileContents .. "\nreturn Includes"))()
if includes ~= nil then
for i = 1, #includes do
RegisterAssetToBeBuilt( includes[i], "particles" )
Using a particle effect is the same as using a mesh. You bind it with an effect and update the transform based on the effect’s world position and then render it. The Particle System uses reference counting, the same way as a mesh. There are only three function exposed: Create, Update and Render.
Just like a mesh, an effect needs to be sent to the Graphics thread using a bucket, and once it is no longer required, its reference count needs to be decremented. There is, however, no reference counting for particle system.
The behaviour of the effect is defined inside Lua files. These lua files are executed as separate processes when the effect is alive inside the game. For communicating between Lua files and C++ interface, some of the following things need to be kept in mind:
A line type Particle inside Lua.
A line type Particle inside Lua.
A quad type Particle inside Lua.
This project has some drawbacks that one must know. It trades performance for flexibility. It allows you to create Particle effects without recompiling the entire game, but since the entire behaviour is happening inside Lua and then that data needs to be transferred to C++, it makes it a tad bit slower. Also, since it is happening inside Lua, it is not that trivial when it comes to debugging.
This project definitely took me more than 30 hours and even though I can spend another 10 hours on it, polishing it and making it more robust, I am really happy and content with what i accomplished. I was able to do what I had originally thought, and I am proud of that.
Mine was a graphics feature, and hence, had code which was very different for different platforms. But I tried to replicate the same thing as I did with meshes and shaders, and in the end, I did a pretty good job. Earlier I had issues with colors happening only in one platform or crashes happening in other and that took me some time to fix it. Also, my particle system had an Update and Render function and both of them used the same buffers (or memory) and yet were being executed on different threads. Figuring that out really took a lot of time. Because of that, OpenGL was not displaying the effects at all in the beginning.
There was another cool thing I did when making it platform independent. I remember JP, my professor, asking us this at the beginning of the class: Is there a way to make a common platform independent header without using any if-defs. I couldn’t come up with any during that time, but for my Particle System, I got clever. I forward declared a structure inside my header file, ParticleInterface. Inside .d3d.cpp and .gl.cpp, I actually defined that structure which contained all the platform specific data structures. Because of this, when you look at the header file, you don’t find any if defs, and it is the same for both platforms. I thought it was pretty cool.
The second most interesting thing I did was with the AssetBuilder thing. The reason was, my Lua files were including other lua files and not returning anything. All the asset files we used so far always returned a table, mine didn’t. Mine also were being executed as a process and then linking with other lua files, This created path issues because lua files are always executed in the same path as the C++.exe. And, I wanted to do something similar to what I did in Shaders, I specify one file, and all the dependent files are automatically built. But the paths then would be different when building the assets and when actually executing them. How do I fix that? Also, some lua files required to return a table (the ones included by other lua files) and some didn’t (the ones only included by C++). How do I make that consistent? because my goal was to have these lua files reusable. Also, I wanted to include other Lua scripts while running the game, not while building the assets. How do I prevent that? So I came up with a very crafty solution.
For the builder, I used a table called Includes inside my Lua assets. There, I specified the Content Folder relative path of all the lua files being included.
And then inside the AssetsBuildFunction, I would read the whole lua file (using file read/write, not dofile) and store it as a string, append “return Includes” and then execute the entire thing using load.
This way, I can get the include table and not load the other lua table while I am building. And also, not care whatever I am doing in that file. So Task 1 accomplished: I have something similar to Shader thing. Now or Task 2: how do I load other Lua files during game?
For that, I came up with another function called Init. Inside Init, I would load the other lua files. But how do I load them? Same as AssetBuilder, but this time, I appended “return Particle” instead and it worked.
Also, note how I appended “Data/” while reading the file. This resolved my path issues. And yes, it took me 5-6 hours to come up with this solution, and a lot (a very lot) of hair pulling, but I think it was pretty neat. At one point, I had almost given up, I was about to compromise on the reusability feature, but it worked.
All in all, I am pretty happy with this project and my accomplishments. There are still a few things I can improve on and make it better, but I doubt if that’s the end goal and if it’s gonna help me much in learning new things. I didn’t make any compromises, developed what I intended and learnt a great deal. I also tried to keep everything as simple as possible so that others can use it. For example, I wanted to use glDrawArraysInstanced to make my effect faster, and I had to change OpenGlExtensions\20170823\glext.h to make that work (that was also a fun thing in itself but I didn’t talk about it since I later decided against using it) but that would have required other students doing a lot more changes on their project. Now I am looking forward to other students using this and curious on their take: is my project too complicated to use or is it just fine?