Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to limit emitted vertices with Geometry shader using Transform feedback?

Tags:

c++

opengl

I'm working on a simple Particle system in OpenGL and I need to generate particles on GPU. Generally I represent particles as GL_POINTS and use only one particle generator point in the beginning. What I do is that I create two Vertex Buffer Objects (VBO) and allocate memory on GPU depending on Max number of particles. Then create two Transform Feedback Buffers (TFB) and each of them is bound to the output of one VBO. First TFB represents input for second VBO and vice versa (buffers are swapped).

Afterwards I generate new vertices (= points, particles) on Geometry shader.

Geometry shader code:

#version 330 compatibility

#extension GL_ARB_geometry_shader4 : enable

layout(points) in;
layout(points, max_vertices = 3) out;

in block{
  vec4 v_WorldPosition;

  vec3 f_Position;
  vec3 f_Color;  
} In[];

out block{
  vec4 v_WorldPosition;
  vec4 v_Color;
} Out;

out feedback{
  vec3 f_Position; 
  vec3 f_Color;  
} feedOut;


const int i = 0; // No need for loop (points. In.length() == 1)

void main()
{  
    feedOut.f_Position = In[i].f_Position; 
    feedOut.f_Color    = In[i].f_Color; 

    if(In[i].f_Color.g == 1){
        feedOut.f_Color.g = 0;
    }

    Out.v_Color = vec4(feedOut.f_Color, 1);
    gl_Position = In[i].v_WorldPosition; 

    EmitVertex();
    EndPrimitive();

    if(In[i].f_Color.g == 1){
        // create new particle
        feedOut.f_Position  = In[i].f_Position; 
        feedOut.f_Color     = vec3(1,0,0);

        Out.v_Color = vec4(feedOut.f_Color, 1);
        gl_Position = In[i].v_WorldPosition;

        EmitVertex();
        EndPrimitive();
    }
  }
}

For the time being I use green color information to determine if the particle should be divided into two. This information is added periodically in vertex shader depending on some timer. Only block feedback is stored into TBF (irrelevant attribute variables deleted from code above).

This works fine, but the problem is when I emit more vertices than my buffer size is. I've expected that no more vertices will be created in such situation, but is seems than newly created vertices override the old ones.

How are additionally emitted vertices stored via Transform Feedback? (I wasn't able to find in any specification). It also seems that it ends in a situation that the first particle is the only one which is stable and all the others are gradually pushed out of the buffer and replaced with the particles which have been created by the first one).

In the final program I want to be able to delete vertices from the pipeline and add new ones depending on some time variables etc. - so I don't have any specified structure of the buffer data.

Is there a way of preventing the override? I need that new particles are not actually created in case of full buffer and only when a particle is deleted (=not emitted) from buffer - new can be created. Is this standard behavior?

Note: Tried on GeForce GT 630M, and GeForce GTX 260 (Windows 7 x64).

like image 595
Bublafus Avatar asked Feb 22 '14 22:02

Bublafus


1 Answers

I think what you should do first is read about gl Query Objects. There's specifically a Query Object for GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN. From the spec: Records the number of primitives written by a Geometry Shader stream to a Transform Feedback object.

Once you have figured out if there are too many primitives(or in the case of a point, a single vertex, which could be color and position and what ever until the call to EndPrimitive()) being written, you can make a different transform feedback update function and corresponding glsl prog that has the same structure as the one that adds primitives except this one just updates what you already have or deletes current ones. Make sure that you know what the size of each primitive (in this case a point) is so that you can query easily your size to make sure you don't go over what you've allocated. Also, it wouldn't be a bad idea to give each a timer so that you can easily decide a lifetime. Similar to what your doing in your vertex shader to see if they should divide but different in that you would check their life in the geometry shader and not emit that vertex if they're dead.

like image 144
Ryan Bartley Avatar answered Sep 24 '22 11:09

Ryan Bartley