Displacement of a particle in vertex shader

Hey! I’m a newbie at GLSL.With that being said:

The problem: What I want to do is send in a particle from OpenGL using VBO and in GLSL move the particle every frame with say a constant velocity.

Code makes this more clear I think.


void main( void )
{
	gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.x +2.0, gl_Vertex.yzw);


	
}

What I want this code to do:
First frame the particle should move 2.0 from its starting possition and frame 2 the particle should be 4.0 from its starting possition etc. That’s how I want it to be.(I’ve tried a “time” variable from OpenGL but that’s not what I want.)

So I want the vertex shader to calculate this every frame without me sending in a new particle every frame. Is that possible?

I’ve been reading up on glMapBuffer but it feels like a detour to send data back to the cpu and then just return it again.

I’ve managed to get the particle to GLSL and from what I can see the vertex shader runs only one time, the first time the particle is sent in to the grafics card.
I know I can’t excpect the vertex shader to know what I want to do but I thought that was the standard.

Can I tell the vertex shader from OpenGL every frame that it should run with all the particles already on the GPU? Or is there any better way?

If anything is unclear I’ll gladly explain more about it.

I greatly appreciate your help!
//Englesson

Your particle data is stored in VBO, right? So it’s already on server (GPU) side, ready for processing.

You can do either absolute or relative modelling.

  1. Absolute:
    p(t) = p(0) + f(t)
    your f(t,x) = t * vector3(2.0,0.0,0.0)
    where t = time passed in seconds
    Can be easily implemented right inside the draw shader (similar to what you posted).

  2. Relative:
    p(t) = f(p(t-delta))
    your f(x) = x + delta*vector3(2.0,0.0,0.0)
    It’s a more universal case that is widely used. In order to do it on GPU, you need to store the result of transformation on server side (look for the term ‘render to vertex buffer’).

For the reference, GPU particles are implemented in KRI engine:
http://code.google.com/p/kri/
It uses TransformFeedback, ping-ponging the particles data between VBO’s, separate from the drawing.

Thanks for the response!

Nr.2 Seems just like what I need, thanks again. I’ll look into ‘render to vertex buffer’.
All I can see in the link you gave me is a short description of the particle system, but no code. Do I need to register ?

Is ‘render to vertex buffer’ only possible on ATI? If so is there an equivalent method for NVIDA?

Under the link is KRI google project page, which contains wiki, bug tracking and, what is more important, code repository (under Mercurial version control). The latter can be browsed right through the google interface:
http://code.google.com/p/kri/source/browse/#hg/engine/code/part

Today, you can render to the vertex buffer in several ways:

  1. Transform feedback: the most straightforward, extension since GL 2.0 and core in GL 3.1
  2. FBO + PBO: render to the texture, than copy it to PBO and treat it like regular buffer object. Requirements are as low as GL 2.0 (I guess)
  3. OpenCL (compute language)

Similar list can be found there:
http://code.google.com/p/kri/wiki/Skinning

From what I’ve understood so far from the “Simple transform feedback” example at
http://cvit.iiit.ac.in/index.php?page=resources

Transform feedback is similar to glMapBuffer+glBufferSubData?
With glMapBuffer you get a pointer to the data when the GPU is finished processing?

Transform feedback: Render to the buffer, send to Server-side-> GPU does what it does best, and then send the buffer back to CPU -> and then you get the buffer back with which you can add more particles etc?

If that’s correct: Is the feedback buffer sent back to CPU side when the whole buffer is done on the GPU? If that’s the case it seems very similar to glMapBuffer + glBufferSubData? Any pros and cons?

If I don’t want to go back to CPU side, is there a way to store the result of the transformation and use that in the next loop? Like the “render to vertex buffer” arrow in this picture is illustrating:
http://www.behardware.com/medias/photos_news/00/16/IMG0016363.jpg

I hope that the answer to that question have nothing to do with OpenCL because I’ve just learned GLSL and I havn’t got the time to learn OpenCL too.

Hopefully the answer lies in FBO + PBO. I’ll check into that now.

Ps. Im very grateful for your helpful answers DmitryM.Ds.

Transform feedback captures the output of the vertex/geometry stage into VBO’s: no CPU nor system bus involved at all.

An example of it used under GL-3.1 context can be found here:
http://www.g-truc.net/post-0277.html

Hey!
I’ve read http://www.opengl.org/registry/specs/NV/transform_feedback.txt which helped alot I think.
I’ve also studied the latter transform feedback example and tried to do something similar. In the example no ping-ponging takes place, right?

The thing is the program compiles but crashes almost immediately when started, with no error message. I’ve tried to find the problem but with no luck.

Hopefully, a kind soul out there can help me.(maybe someone else than DmitryM who’ve done too much for me already.)

I know it’s really hard to put your mind into new code but I’ll paste some interesting parts of the code below:


//Program defined as:GLuint program;
program = glCreateProgram();
    glAttachShader( program, vertexShader );
    glAttachShader( program, fragmentShader );
//Set gl_Position to be fedback.Done before linking.
    GLchar const * Strings[] = {"gl_Position"};
    glTransformFeedbackVaryings(program, 1, Strings, GL_SEPARATE_ATTRIBS);
    glLinkProgram( program );

Inilization of the two identical “ping-pong” buffers.


    glGenBuffers(1, vTransformParticleBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, *vTransformParticleBuffer);
    glBufferData(GL_ARRAY_BUFFER, MaxNrOfParticles*3*sizeof(float) , 0, GL_DYNAMIC_COPY);

    glGenBuffers(1, vFeedbackParticleBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, *vFeedbackParticleBuffer);
    glBufferData(GL_ARRAY_BUFFER, MaxNrOfParticles*3*sizeof(float) , 0, GL_DYNAMIC_COPY);
//Check if error occured
    GLuint errorID = glGetError();
    if (errorID != GL_NO_ERROR)
    {
        printf("OpenGL error2: %s
", gluErrorString(errorID));
        printf("Attempting to proceed anyway. Expect rendering errors or a crash.
");
    }
    glBindBuffer(GL_ARRAY_BUFFER, 0);

And the code for drawing and ping-ponging. Query code commented because I don’t know if I need it when doing it this way.


glUseProgram( program );


//GLuint Query;
//glGenQueries(1,&Query);

//Pointsprite related code.
//----------------------------------------------------
    GLuint pointSize = 20;
    glPointSize(pointSize);
    glEnable(GL_BLEND);
    glBlendFunc( GL_SRC_ALPHA, GL_ONE);
    glBindTexture(GL_TEXTURE_2D, texID); // Activate texture
    glEnable(GL_POINT_SPRITE_ARB);
    glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, 
GL_TRUE);
//----------------------------------------------------
    if (ping) //declared as GLboolean ping = GL_TRUE;
    {
        currentBuffers[0] = vFeedbackParticleBuffer;
        currentBuffers[1] = vTransformParticleBuffer;
        ping = GL_FALSE;  //ping == pong :D
    }
    else
    {
        currentBuffers[0] = vTransformParticleBuffer;
        currentBuffers[1] = vFeedbackParticleBuffer;
        ping = GL_TRUE;
    }

    glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, currentBuffers[0]);

    glBindBuffer(GL_ARRAY_BUFFER, currentBuffers[1]);
//glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, Query);

//Spawns 9 particles to the bound buffer only first time.
//Implemented to later be able to spawn particles with a push of a button.
if (spawnParticles)//GLuint spawnParticles = GL_TRUE;
    {
//int index =0; declared elsewhere.
        glBufferSubData(GL_ARRAY_BUFFER, index, 9*3*sizeof(float), particles2);
        index=9*3*sizeof(float);
        spawnParticles = GL_FALSE;
        *nrOfParticles += 9;
    }


    glBeginTransformFeedback(GL_POINTS);

    glVertexPointer(3, GL_FLOAT, 0, 0);
    glEnableClientState(GL_VERTEX_ARRAY);

    glDrawArrays(GL_POINTS, 0, *nrOfParticles);

    glDisableClientState(GL_VERTEX_ARRAY);

    glEndTransformFeedback();

//glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);

    glBindBuffer( GL_ARRAY_BUFFER, 0);
    glDisable(GL_POINT_SPRITE_ARB);
    glBindTexture(GL_TEXTURE_2D, 0); // Deactivate the texture again

    glDisable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ZERO);

    glUseProgram(0);



}

What I think this code should do:
First time it binds BindBufferBase to the feedbackbuffer and then I bind the transFormbuffer to be able to draw its data. Because I set the bindBufferBase to the feedbackbuffer the particle positions,gl_Position, after the vertex shader(no geometry shader), should be saved to the feedbackbuffer. And the second time the draw-function is used the transformbuffer is bound to bindBufferBase and the content of the feedbackBuffer should be drawn into the transformbuffer. And so on and on.

I’ve done some simple std::cout before functions and after functions etc, to find where the program crashes and the “first” crash is at:

glTransformFeedbackVaryings(program, 1, Strings, GL_SEPARATE_ATTRIBS);

Which is the first call to any tranform feedback related function.

I greatly appriciate any answers.
//Englesson

Maybe last post should be moved to: “OpenGL coding: advanced”? If so, can moderator please move.

Hi again :slight_smile:

If you are on NV card, then it’s probably a bug. I tried to get it work as well on NV, but failed with the same function TransformFeedbackVaryins, that was crashing.
My primary platform is ATI and I haven’t reported a bug to NV still… You can take a chance, or, at least, try on ATI.

Next, gl_Position is a built-in ‘vec4’ while your buffers are created for ‘vec3’, so there will be an access violation or some undefined driver behavior. I advice choosing your own output varying with correct type (vec3).

A small extra tip: TF somehow works better with queries.

<-- (Now tears of joy)
Hey!
First of all thank you for taking time to help me.

“Next, gl_Position is a built-in ‘vec4’ while your buffers are created for ‘vec3’, so there will be an access violation or some undefined driver behavior. I advice choosing your own output varying with correct type (vec3).”

Oh, I did not see that! I’ll fix it and try it on an ATI platform! And get back to you!

Ps. I don’t think you realize how much I appriciate your help. Ds.

Status update:

I’ve changed and tried the code on a new computer with a higher version of OpenGL but still Nvidia. It doesn’t crash but no point sprites are visible. I ran it without the transform feedback and it worked.

I’ve tried to find the problem with a query.

glGetQueryObjectuiv with GL_QUERY_RESULT as pname returns 0. (done after glEndQuery)

Subsequent rendering will increment the counter once for every sample that passes the depth test. When glEndQuery is executed, the samples-passed counter is assigned to the query object’s result value. This value can be queried by calling glGetQueryObject with pname GL_QUERY_RESULT.

So none of my particles passes the depth test? I can’t understand why.

Seems the problem lies in the transform feedback code.

I followed your advice and made an own output varying variable in the vertex shader:

out varying vec3 pos;
and set the final postion to that variable, and at last
gl_Position = vec4(pos,1);

and in main application I changed gl_Position to pos:

GLchar const * Strings[] = {"pos"};
glTransformFeedbackVaryings(program, 1, Strings,GL_SEPARATE_ATTRIBS);

I’ve also used:

GLint streamV;
glGetProgramiv(program,GL_TRANSFORM_FEEDBACK_VARYINGS,&streamV);
std::cout << "nrOfStreamingVaryings: " << streamV;

Which returns the value 1.

Can my problem have something to do with the fact that I enable point sprites before I enable transform feedback for GL_POINTS ?(Check code) Transform feedback only works for GL_POINTS(?) and some undefined error happens because I enabled point sprites?

Tomorrow I’ll try to render the transformbuffer with transform feedback without enabling point sprites and use:
glEnable(GL_RASTERIZER_DISCARD);
And then draw the feedbackbuffer with point sprites enabled.

Hope that solves the problem or does anyone else see any mistakes ?

Thanks in advance.
//Englesson

I’ve now tried to render the data like I said before:
First render:

  • No point sprites
  • Shaders active
  • Discarding rasterization
  • Transform feedback

Second render:

  • Point sprites
  • Shaders inactive

Guess what? It works, finally.

I hope this thread can help others who want to use transform feedback with VBOs. There really arent many tutorials or examples of it at all.

Final note: Just want to thank you once more for all your help,DmitryM.

Good to know you got it working:)
It’s true that TF doesn’t get enough attention from the public currently.
More than that, your code works on NV, what is a pretty good news for me:)