After seeing Ian’s latest update on his awesome particles system, I am shifting the focus of my own project a bit, moving away from the goal of making an entire particles engine in the shader to something more attainable: use GLSL shaders for what they are designed for: making visual effects. Below is attempt at making some abstract art using pure code. The base shape is a simple plane.

You might notice that some of the shader code looks strange, that’s because I am trying to keep things simple by forcing myself to use the latest version of OpenGL Shading Language available on my computer hardware, so for a Geforce 8, that’s OpenGL 3.3 | GLSL 3.3.
#version 120
#vertex shader
in vec4 vertex;
uniform float timer;
void main() {
vec4 v = vertex;
v.z = sin(timer+v.y+v.x)*0.5+v.z;
v.x = sin(timer*10.0+v.y+v.y)*0.2+v.x;
gl_Position = gl_ModelViewProjectionMatrix * v;
}
#==========================
#version 330
#geometry shader
layout(triangles) in;
layout(triangle_strip) out;
out vec2 texCoord;
#define radius 0.01
#define layer 1
void main() {
//for(int i = 0; i < gl_in.length(); i++) { // avoid duplicate draw
for (int j=0; j<layer; j++){
vec4 p = gl_in[0].gl_Position;
texCoord = vec2(1.0,1.0);
gl_Position = vec4(p.r+radius, p.g+radius+j*0.05, p.b, p.a);
EmitVertex();
texCoord = vec2(0.0,1.0);
gl_Position = vec4(p.r-radius, p.g+radius+j*0.05, p.b, p.a);
EmitVertex();
texCoord = vec2(1.0,0.0);
gl_Position = vec4(p.r+radius, p.g-radius+j*0.05, p.b, p.a);
EmitVertex();
texCoord = vec2(0.0,0.0);
gl_Position = vec4(p.r-radius, p.g-radius+j*0.05, p.b, p.a);
EmitVertex();
EndPrimitive();
}
//}
}
#========================================
#version 330
#fragment shader
in vec2 texCoord;
out vec4 outColor;
uniform sampler2D col;
uniform float emit, alpha;
void main(void) {
// load color texture
vec4 color;
color = texture2D(col, texCoord);
// apply material panel values
color.rgb *= emit;
color.a *= alpha;
outColor = color;
}
The first section, the vertex shader, is executed for each vertex of the geometry, it is here that I apply the deformation to form the base shape of the particle systems. The resulting coordinates is projected from modelspace onto viewspace. This is important, because it saves the next step from becoming overly complex! The geometry that follows is able to do per-primitive operations on the vertex, here I take each vertex from the previous stage(which is already projected into viewspace), and ‘expand’ that into a billboard by creating a quad for each point. The quad naturally faces the camera, since everything is already in viewspace. The final stage of the pipeline is the fragment shader, which applies a texture onto the quad.
One blatant oversight of this approach is that it does not take into account the viewport aspect ratio, thus the generated particles will only look square on a 1:1 canvas. None unity aspect-ratio will stretch the billboard.
As you can see, the code is very short, but being GLSL, the program is executed on the graphic hardware, which is highly tuned for this type of computation. Freeing the CPU to do other things.