SourceForge.net Logo
Home
Documentation
Tutorials
    Beginning
    Gears
    Noise
    Bumpmapping
    Point sprites
    Hello World
    Armature
    Geometryshader
    Toolscripting
    Keyframe animation
    Instancing
    Bezier Surface
    Deferred shading
    Depth peeling
    Particle System
Links
Support This Project
OpenGL
Shader Model 4.0 based particle system
Shader Model 4 raises the GPUs flexibility. Two important new features beside the
geometry shader and instancing are bindable uniforms and Transform feedback.
With bindable uniforms it is possible to access a buffer object with random access. This
is useful for accessing the data of other vertices.
Transform feedback allows to stream out the results of a vertex shader, into a buffer
object. This feature makes it possible to handle particle physics on a GPU without
processing data on a CPU.

As first the required stuff should be generated by entering some lines into the console:

Node = World.addNode();
Node.addScript();
Node.addVertexShader("ParticleVertexshader");
Node.addVertexShader("SphereVertexshader");
Node.addFragmentShader("SphereFragmentshader");
Node.addMesh("Particle");
Node.Particle.setNumOfVertices(256);
Node.Particle.addVertex().setDim(4);
Node.Particle.addVertex().setDim(4); //rename to "Position_1"
Node.Particle.addVertex().setDim(4); //rename to "Position_2"
Node.Particle.addVector().setDim(3); //rename to "Speed_1"
Node.Particle.addVector().setDim(3); //rename to "Speed_1"

for ( i = 0; i < 256; i++)
Node.Particle.Vertex.set(i,Math.random()*2-1,Math.random()*2-1,Math.random()*2-1);

Finally add a sphere Mesh (Testobjects from Nodes context menu). And copy the code into
the codeboxes:

ParticleVertexshader:

#define active
active varying vec4 position_out;
active varying vec3 speed_out;

attribute vec4 position_in;
attribute vec3 speed_in;

uniform float Pointsize;

void main(void){
speed_out = speed_in;
speed_out.z -= 0.01;
position_out = position_in;
position_out.xyz += speed_out.xyz * 0.21;

if (position_out.z < 0.0){
speed_out.xyz = vec3(0.0, 0.0, 1.4) + gl_Vertex.zyx * 0.3;
position_out.xyz = vec3(0.0, 0.0, 0.0);
}

//dummy can be used for rendering pointsprites
//like in the youtube video
//elsewhere the result will be discarded
vec4 v = vec4(position_out.xyz,1.0);
gl_Position = gl_ModelViewProjectionMatrix * v;
//vec4 mod = gl_ModelViewMatrix * v;
//gl_PointSize = 5 *Pointsize/ -mod.z ;
}


SphereVertexshader:

#extension GL_EXT_gpu_shader4 : enable
bindable uniform vec4 pos[256];
varying vec3 N;
void main (void){
vec4 vert = gl_Vertex + vec4(pos[gl_InstanceID].xyz, 0.0);
gl_Position = gl_ModelViewProjectionMatrix * vert;
N = gl_NormalMatrix * gl_Normal;
}


SphereFragmentshader:

varying vec3 N;
void main (void){
float light = max(0.0,dot(normalize(N), vec3(0.0, 0.0, 1.0)));
gl_FragColor = vec4(1.0, 0.0, 0.0, 0.0) * light;
}


Script:

World.Cam.LoadIdenty();
World.Cam.Translate(0,10,30);

shader = gl.Shader(ParticleVertexshader);

pos_in = shader.Loc("position_in");
speed_in = shader.Loc("speed_in");

sphereshader = gl.Shader(SphereVertexshader,SphereFragmentshader);
sphereshader.Uniform("pos",World.Node.Particle.Position_2);

pp = 0;

Position = Array(Particle.Position_1,Particle.Position_2,Particle.Position_1);
Speed = Array(Particle.Speed_1,Particle.Speed_2,Particle.Speed_1);

function render(){
pp = (pp + 1) % 2;

gl.Rotate(-90, 1,0,0);
shader.Bind();

Position[pp].TransformFeedbackBind("position_out");
Speed[pp].TransformFeedbackBind("speed_out");

Particle.Vertex.Bind(); //contains random numbers
Position[pp+1].Bind(pos_in);
Speed[pp+1].Bind(speed_in);

gl.BeginTransformFeedback(gl.POINTS,true);
Particle.Draw(gl.POINTS);
gl.EndTransformFeedback();

Particle.Vertex.UnbindAll(); //Unbind all bounded components

sphereshader.Bind();
sphereshader.Uniform("pos",Position[pp+1]);

Sphere.Vertex.Bind();
Sphere.Normal.Bind();
Sphere.Index.DrawInstanced(256);
}


Now start the script. The result should be similar like in that video (but without the
pointsprite glow). The 256 in these scripts can be replaces by a higher number. the
limit (by the bindable uniforms) are 4096 Spheres (=16384 floats or 64k bytes).

If nothing is displayed, save the project (unknown bug)


4096 Spheres (only a few values in ParticleVertexshader are modified)





Older Version rendering Pointsprites instead spheres
EDIT