Tutorial 2: Emission and Update - tiagodinis/GParticles GitHub Wiki
In this tutorial, we'll explore the emission and update events, and see how they affect our particles behavior.
We start by creating a new copy of our "/Tutorial_1" folder in the same directory, naming it "/Tutorial_2". We also change the name of the project definition file to "Tutorial_2.xml". In this file, we'll keep every configuration from Tutorial 1 apart from the prefab attributes being used in the emission and update tags. Instead, we are going to define event functions in files that will later be referenced on the corresponding event tags. These files use the glsl syntax, so I recommend you get a hold of a text editor that supports glsl syntax highlighting (such as Sublime text or Notepad++), if you don't already.
Starting with the update event, we create a file named "update.glsl" with an empty update function.
void update(){}Then, we reference it in "Tutorial_2.xml" alongside another file named "updateMain.glsl". This file is stored in "App/templates" and contains the boilerplate logic of the update event, which, in 99% of cases, won't require any change. You can visit the extensibility page to learn more about templates, but just know that it will be "updateMain.glsl" that will call our update function.
<update>
<file path="projects/Tutorial_2/update.glsl" />
<file path="templates/updateMain.glsl" />
</update>If we run this project we can see the only difference in regards to the Tutorial 1 example is that our particles are stationary. Let's change this by decreasing the y component of every particle position with the following line:
void update()
{
@positions[gid].y -= 1 * @deltaTime;
}Here, we are accessing the particle positions buffer with gid, the current particle global invocation ID, and decreasing its y component by 1 * @deltaTime. deltaTime is a float variable that stores the elapsed time in milliseconds since the previous iteration and is used to guarantee frame independent data processing. In this case, we are decreasing the y component by 1 unit/second, so if 20 milliseconds have passed since the last iteration, we'll only decrease y by 0.02 at this point.
The @ character is used in GParticles as a generic, easy way to reference instance resources. When loading a project and all its accompanying files, every @ will be replaced by the corresponding name of the particle system. In this tutorial, since the name attribute on the psystem tag has "simple" as its value, @positions[gid].y -= 1 * @deltaTime is the same as writing simple_positions[gid].y -= 1 * simple_deltaTime. Another advantage of using @s is the ability to reuse logic code. Files on the "/App/templates" folder make use of the @ character so they can be referenced by different particle systems, so long as these systems provide the required instance resources.
If you want to learn more about how resources are handled in GParticles, be sure to check the GParticles Resources and Header Generation pages.
If we run the project we should have the following effect:
Now let's try and add some randomness to the particles movement. For this, we can use the "utilities.glsl" module that already provides us with the required functionality.
<update>
<file path="modules/utilities.glsl" />
<file path="projects/Tutorial_2/update.glsl" />
<file path="templates/updateMain.glsl" />
</update>The "utilities.glsl" module defines the function randInRange, that, surprise, surprise, generates random floats in the given range. We can use this to alter every component of our particle positions in update:
void update()
{
vec3 newComponents = vec3( randInRange(-1,1),
randInRange(-1,1),
randInRange(-1,1));
@positions[gid].xyz += newComponents * @deltaTime;
}Great! Now let's work with the emission event. This event operates in a very similar way as the update event, but it's commonly used to initialize particle data values. For this event, we are going to use the "utilities.glsl" and "emission.glsl" modules, and the default emission template file. Basically, the "emissionMain.glsl" template just checks if it is possible to create another particle, calling the emission function if that is indeed the case.
<emission>
<override type="atomic" name="emissionAttempts" value=0/>
<file path="modules/utilities.glsl" />
<file path="modules/emission.glsl" />
<file path="projects/Tutorial_2/emission.glsl" />
<file path="templates/emissionMain.glsl" />
</emission>You can also see we used an override on the emissionAttempts atomic, but don't mind it too much right now. Just know it's an "emissionMain.glsl" requirement that you must define every time you use this template.
On the emission function we create green particles that live for 5 seconds and have their positions stacked along the y axis:
void emission()
{
@lifetimes[gid] = 5;
@positions[gid].xyz = vec3(0, gid / @maxParticles, 0);
@colors[gid] = vec4(0.1,0.9,0.1,1);
}Nice. Finally, we apply some changes on the emission and update functions to make use of the functionality in the modules we just referenced on the emission tag.
// emission.glsl
void emission()
{
@lifetimes[gid] = 5;
@positions[gid] = spherePositionGenerator(1.5, false);
@velocities[gid].xyz = velocityGenerator(@positions[gid].xyz, vec3(0), 0.1);
@colors[gid] = vec4(0.1,0.9,0.1,1);
}
-----------------------------------------------------------------------------------
// update.glsl
void update()
{
@positions[gid].xyz += @velocities[gid].xyz * @deltaTime;
}Oh, snap! If it ain't our Tutorial 1 particle system! So now you know the prefabs we got rid off, in the beginning of the tutorial, were hiding this very same functionality. Good. We are ready for Tutorial 3, where we explore how to render particles in ways different than boring points.
Exercises:
- Define an update function so that particles move away from the system origin while their lifetime is > 1 and, when that is no longer true, towards it.
- Add a function to "emission.glsl" that can generate particle positions inside a box.
- Take a prolonged peek inside the module and template files used. Now run the example without the emissionAttempts atomic override and try to understand its importance.



